mirror of
https://github.com/DSpace/DSpace.git
synced 2025-10-15 05:53:08 +00:00
DS-3542 expiration time configurable
This commit is contained in:
@@ -1,2 +1 @@
|
||||
-- This adds an extra column to the eperson table where we save a salt for stateless authentication
|
||||
ALTER TABLE eperson ADD session_salt varchar(16);
|
||||
alter table eperson add session_salt varchar(16);
|
@@ -18,24 +18,30 @@ import java.sql.SQLException;
|
||||
import java.util.Collection;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api")
|
||||
@RequestMapping("/")
|
||||
public class StatusRestController {
|
||||
|
||||
@RequestMapping(value = "/status", method = RequestMethod.GET)
|
||||
public Status status(HttpServletRequest request, HttpServletResponse response) throws SQLException {
|
||||
@RequestMapping(value="/status", method = RequestMethod.GET)
|
||||
public String status(HttpServletRequest request, HttpServletResponse response) throws SQLException {
|
||||
|
||||
Context context = ContextUtil.obtainContext(request);
|
||||
//context.getDBConnection().setAutoCommit(false); // Disable autocommit.
|
||||
|
||||
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
|
||||
if(authentication != null && !(authentication.getPrincipal().equals("anonymousUser"))) {
|
||||
Collection<SimpleGrantedAuthority> authorities = (Collection<SimpleGrantedAuthority>) authentication.getAuthorities();
|
||||
|
||||
Collection<SimpleGrantedAuthority> authorities = (Collection<SimpleGrantedAuthority>) authentication.getAuthorities();
|
||||
|
||||
context.setCurrentUser(EPersonServiceFactory.getInstance().getEPersonService().findByEmail(context, authentication.getName()));
|
||||
|
||||
EPerson current = context.getCurrentUser();
|
||||
return new Status(current);
|
||||
context.setCurrentUser(EPersonServiceFactory.getInstance().getEPersonService().findByEmail(context, authentication.getName()));
|
||||
|
||||
EPerson current = context.getCurrentUser();
|
||||
String status = "EPerson: " + current.getEmail() + "\nFull name: " + current.getFullName() + "\nAuthorities: \n";
|
||||
for (SimpleGrantedAuthority authority: authorities) {
|
||||
status += authority.getAuthority();
|
||||
}
|
||||
return status;
|
||||
|
||||
} else {
|
||||
return "Not authenticated";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -25,14 +25,13 @@ public class CustomLogoutHandler implements LogoutHandler {
|
||||
|
||||
public void logout(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) {
|
||||
Cookie cookie = WebUtils.getCookie(httpServletRequest,"access_token");
|
||||
EPerson ePerson = tokenAuthenticationService.getAuthentication(cookie.getValue(), httpServletRequest);
|
||||
Context context = null;
|
||||
try {
|
||||
context = ContextUtil.obtainContext(httpServletRequest);
|
||||
} catch (SQLException e) {
|
||||
log.error("Unable to obtain context", e);
|
||||
}
|
||||
EPerson ePerson = tokenAuthenticationService.getAuthentication(cookie.getValue(), httpServletRequest, context);
|
||||
|
||||
ePerson.setSessionSalt("");
|
||||
try {
|
||||
context.commit();
|
||||
|
@@ -37,16 +37,17 @@ public class EPersonRestAuthenticationProvider implements AuthenticationProvider
|
||||
context = new Context();
|
||||
String name = authentication.getName();
|
||||
String password = authentication.getCredentials().toString();
|
||||
HttpServletRequest httpServletRequest = request;
|
||||
List<GrantedAuthority> grantedAuthorities = new ArrayList<>();
|
||||
|
||||
|
||||
int implicitStatus = authenticationService.authenticateImplicit(context, null, null, null, request);
|
||||
int implicitStatus = authenticationService.authenticateImplicit(context, null, null, null, httpServletRequest);
|
||||
|
||||
if (implicitStatus == AuthenticationMethod.SUCCESS) {
|
||||
log.info(LogManager.getHeader(context, "login", "type=implicit"));
|
||||
return new DSpaceAuthentication(name, password, grantedAuthorities);
|
||||
} else {
|
||||
int authenticateResult = authenticationService.authenticate(context, name, password, null, request);
|
||||
int authenticateResult = authenticationService.authenticate(context, name, password, null, httpServletRequest);
|
||||
if (AuthenticationMethod.SUCCESS == authenticateResult) {
|
||||
|
||||
log.info(LogManager
|
||||
|
@@ -10,7 +10,6 @@ import org.dspace.eperson.EPerson;
|
||||
import org.dspace.eperson.Group;
|
||||
import org.dspace.eperson.factory.EPersonServiceFactory;
|
||||
import org.dspace.eperson.service.EPersonService;
|
||||
import org.dspace.services.factory.DSpaceServicesFactory;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.security.crypto.keygen.KeyGenerators;
|
||||
@@ -29,22 +28,20 @@ public class JWTTokenHandler {
|
||||
private static final Logger log = LoggerFactory.getLogger(JWTTokenHandler.class);
|
||||
|
||||
//TODO configurable through config files
|
||||
private String jwtKey;
|
||||
private static String jwtKey = "thisisatestsecretkeyforjwttokens";
|
||||
private EPersonService ePersonService = EPersonServiceFactory.getInstance().getEPersonService();
|
||||
public static final String EPERSON_ID = "eid";
|
||||
public static final String SPECIAL_GROUPS = "sg";
|
||||
|
||||
|
||||
public JWTTokenHandler() {
|
||||
jwtKey = DSpaceServicesFactory.getInstance().getConfigurationService().getProperty("jwt.secret", "defaultjwtkeysecret");
|
||||
System.out.println(jwtKey);
|
||||
}
|
||||
|
||||
public EPerson parseEPersonFromToken(String token, HttpServletRequest request, Context context) throws JOSEException, ParseException, SQLException {
|
||||
public EPerson parseEPersonFromToken(String token, HttpServletRequest request) throws JOSEException, ParseException, SQLException {
|
||||
|
||||
SignedJWT signedJWT = SignedJWT.parse(token);
|
||||
Context context = new Context();
|
||||
EPerson ePerson = ePersonService.find(context, UUID.fromString(signedJWT.getJWTClaimsSet().getClaim(EPERSON_ID).toString()));
|
||||
String ipAddress = getIpAddress(request);
|
||||
String ipAddress = request.getHeader("X-FORWARDED-FOR");
|
||||
if (ipAddress == null) {
|
||||
ipAddress = request.getRemoteAddr();
|
||||
}
|
||||
JWSVerifier verifier = new MACVerifier(jwtKey + ePerson.getSessionSalt() + ipAddress);
|
||||
|
||||
//If token is valid and not expired return eperson in token
|
||||
@@ -61,7 +58,10 @@ public class JWTTokenHandler {
|
||||
public String createTokenForEPerson(Context context, HttpServletRequest request, EPerson ePerson, List<Group> groups) throws JOSEException {
|
||||
StringKeyGenerator stringKeyGenerator = KeyGenerators.string();
|
||||
String salt = stringKeyGenerator.generateKey();
|
||||
String ipAddress = getIpAddress(request);
|
||||
String ipAddress = request.getHeader("X-FORWARDED-FOR");
|
||||
if (ipAddress == null) {
|
||||
ipAddress = request.getRemoteAddr();
|
||||
}
|
||||
JWSSigner signer = new MACSigner(jwtKey + salt + ipAddress);
|
||||
|
||||
List<String> groupIds = groups.stream().map(group -> group.getID().toString()).collect(Collectors.toList());
|
||||
@@ -87,13 +87,4 @@ public class JWTTokenHandler {
|
||||
return signedJWT.serialize();
|
||||
}
|
||||
|
||||
|
||||
public String getIpAddress(HttpServletRequest request) {
|
||||
String ipAddress = request.getHeader("X-FORWARDED-FOR");
|
||||
if (ipAddress == null) {
|
||||
ipAddress = request.getRemoteAddr();
|
||||
}
|
||||
return ipAddress;
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -67,7 +67,7 @@ public class StatelessAuthenticationFilter extends BasicAuthenticationFilter{
|
||||
} catch (SQLException e) {
|
||||
log.error("Unable to obtain context from request", e);
|
||||
}
|
||||
EPerson eperson = tokenAuthenticationService.getAuthentication(token, request, context);
|
||||
EPerson eperson = tokenAuthenticationService.getAuthentication(token, request);
|
||||
boolean isAdmin = false;
|
||||
try {
|
||||
isAdmin = authorizeService.isAdmin(context, eperson);
|
||||
|
@@ -36,8 +36,8 @@ public class TokenAuthenticationService {
|
||||
|
||||
public void addAuthentication(HttpServletRequest request, HttpServletResponse response, String email) {
|
||||
try {
|
||||
EPerson ePerson = ePersonService.findByEmail(ContextUtil.obtainContext(request), email);
|
||||
Context context = ContextUtil.obtainContext(request);
|
||||
EPerson ePerson = ePersonService.findByEmail(context, email);
|
||||
List<Group> groups = authenticationService.getSpecialGroups(context, request);
|
||||
String token = jwtTokenHandler.createTokenForEPerson(context, request, ePerson, groups);
|
||||
//TODO token is saved in a cookie, but might be better to save it in http header
|
||||
@@ -51,9 +51,9 @@ public class TokenAuthenticationService {
|
||||
|
||||
}
|
||||
|
||||
public EPerson getAuthentication(String token, HttpServletRequest request, Context context) {
|
||||
public EPerson getAuthentication(String token, HttpServletRequest request) {
|
||||
try {
|
||||
EPerson ePerson = jwtTokenHandler.parseEPersonFromToken(token, request, context);
|
||||
EPerson ePerson = jwtTokenHandler.parseEPersonFromToken(token, request);
|
||||
return ePerson;
|
||||
} catch (JOSEException e) {
|
||||
log.error("Jose error", e);
|
||||
|
@@ -11,7 +11,6 @@ import org.springframework.security.config.annotation.web.configuration.EnableWe
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
import org.springframework.security.config.http.SessionCreationPolicy;
|
||||
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
||||
import org.springframework.security.web.authentication.logout.HttpStatusReturningLogoutSuccessHandler;
|
||||
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
|
||||
|
||||
|
||||
@@ -29,6 +28,8 @@ public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http.headers().cacheControl();
|
||||
|
||||
|
||||
http
|
||||
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
|
||||
.exceptionHandling().and()
|
||||
@@ -36,16 +37,16 @@ public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
|
||||
.servletApi().and()
|
||||
.csrf().disable()
|
||||
|
||||
.logout().addLogoutHandler(customLogoutHandler).logoutRequestMatcher(new AntPathRequestMatcher("/api/logout")).logoutSuccessHandler(new HttpStatusReturningLogoutSuccessHandler()).permitAll()
|
||||
.logout().addLogoutHandler(customLogoutHandler).logoutRequestMatcher(new AntPathRequestMatcher("/logout")).logoutSuccessUrl("/status").permitAll()
|
||||
.and()
|
||||
.authorizeRequests()
|
||||
|
||||
.antMatchers( "/api/login").permitAll()
|
||||
.antMatchers(HttpMethod.GET, "/api/status").permitAll()
|
||||
.antMatchers(HttpMethod.POST, "/login").permitAll()
|
||||
.antMatchers(HttpMethod.GET, "/status").permitAll()
|
||||
|
||||
.and()
|
||||
|
||||
.addFilterBefore(new StatelessLoginFilter("/api/login", authenticationManager()), UsernamePasswordAuthenticationFilter.class)
|
||||
.addFilterBefore(new StatelessLoginFilter("/login", authenticationManager()), UsernamePasswordAuthenticationFilter.class)
|
||||
|
||||
// Custom Token based authentication based on the header previously given to the client
|
||||
.addFilterBefore(new StatelessAuthenticationFilter(authenticationManager()), UsernamePasswordAuthenticationFilter.class);
|
||||
|
@@ -50,4 +50,5 @@
|
||||
plugin.sequence.org.dspace.authenticate.AuthenticationMethod = org.dspace.authenticate.PasswordAuthentication
|
||||
|
||||
|
||||
jwt.secret = thisisatestsecretkeyforjwttokens
|
||||
jwt.token.secret = thisisatestsecretkeyforjwttokens
|
||||
jwt.token.expiration = 1800000
|
Reference in New Issue
Block a user