DS-3542 Reuse salt if not expired

This commit is contained in:
frederic
2017-11-13 09:45:23 +01:00
parent dd8fbedf90
commit 3fb72221ca
8 changed files with 79 additions and 28 deletions

View File

@@ -92,6 +92,9 @@ public class EPerson extends DSpaceObject implements DSpaceObjectLegacySupport
@Transient @Transient
protected transient EPersonService ePersonService; protected transient EPersonService ePersonService;
@Transient
private Date previousActive;
/** /**
* Protected constructor, create object using: * Protected constructor, create object using:
* {@link org.dspace.eperson.service.EPersonService#create(Context)} * {@link org.dspace.eperson.service.EPersonService#create(Context)}
@@ -373,6 +376,7 @@ public class EPerson extends DSpaceObject implements DSpaceObjectLegacySupport
*/ */
public void setLastActive(Date when) public void setLastActive(Date when)
{ {
this.previousActive = lastActive;
this.lastActive = when; this.lastActive = when;
} }
@@ -444,4 +448,12 @@ public class EPerson extends DSpaceObject implements DSpaceObjectLegacySupport
public void setSessionSalt(String sessionSalt) { public void setSessionSalt(String sessionSalt) {
this.sessionSalt = sessionSalt; this.sessionSalt = sessionSalt;
} }
public Date getPreviousActive() {
if (previousActive == null) {
return new Date(0);
}
return previousActive;
}
} }

View File

@@ -7,19 +7,29 @@
*/ */
package org.dspace.app.rest.security; package org.dspace.app.rest.security;
import java.util.Collection; import org.dspace.eperson.EPerson;
import java.util.List;
import org.springframework.security.core.Authentication; import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.GrantedAuthority;
import java.util.Collection;
import java.util.List;
public class DSpaceAuthentication implements Authentication { public class DSpaceAuthentication implements Authentication {
private EPerson ePerson;
private String username; private String username;
private String password; private String password;
private List<GrantedAuthority> authorities; private List<GrantedAuthority> authorities;
private boolean authenticated = true; private boolean authenticated = true;
public DSpaceAuthentication (EPerson ePerson, List<GrantedAuthority> authorities) {
this.ePerson = ePerson;
this.username = ePerson.getEmail();
this.authorities = authorities;
}
public DSpaceAuthentication (String username, String password, List<GrantedAuthority> authorities) { public DSpaceAuthentication (String username, String password, List<GrantedAuthority> authorities) {
this.username = username; this.username = username;
this.password = password; this.password = password;
@@ -57,4 +67,8 @@ public class DSpaceAuthentication implements Authentication {
public String getName() { public String getName() {
return username; return username;
} }
public EPerson getEPerson() {
return ePerson;
}
} }

View File

@@ -118,7 +118,7 @@ public class EPersonRestAuthenticationProvider implements AuthenticationProvider
//Pass the eperson ID to the request service //Pass the eperson ID to the request service
requestService.setCurrentUserId(ePerson.getID()); requestService.setCurrentUserId(ePerson.getID());
return new DSpaceAuthentication(ePerson.getEmail(), password, getGrantedAuthorities(context, ePerson)); return new DSpaceAuthentication(ePerson, getGrantedAuthorities(context, ePerson));
} else { } else {
log.info(LogManager.getHeader(context, "failed_login", "No eperson with an non-blank e-mail address found")); log.info(LogManager.getHeader(context, "failed_login", "No eperson with an non-blank e-mail address found"));

View File

@@ -27,9 +27,11 @@ import com.nimbusds.jwt.JWTClaimsSet;
import com.nimbusds.jwt.SignedJWT; import com.nimbusds.jwt.SignedJWT;
import com.nimbusds.jwt.util.DateUtils; import com.nimbusds.jwt.util.DateUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.dspace.authorize.AuthorizeException;
import org.dspace.core.Context; import org.dspace.core.Context;
import org.dspace.eperson.EPerson; import org.dspace.eperson.EPerson;
import org.dspace.eperson.Group; import org.dspace.eperson.Group;
import org.dspace.eperson.factory.EPersonServiceFactory;
import org.dspace.eperson.service.EPersonService; import org.dspace.eperson.service.EPersonService;
import org.dspace.servicemanager.config.DSpaceConfigurationService; import org.dspace.servicemanager.config.DSpaceConfigurationService;
import org.dspace.services.ConfigurationService; import org.dspace.services.ConfigurationService;
@@ -59,6 +61,9 @@ public class JWTTokenHandler {
@Autowired @Autowired
private EPersonClaimProvider ePersonClaimProvider; private EPersonClaimProvider ePersonClaimProvider;
@Autowired
private EPersonService ePersonService;
public JWTTokenHandler() { public JWTTokenHandler() {
//TODO move properties to authentication module //TODO move properties to authentication module
@@ -118,25 +123,21 @@ public class JWTTokenHandler {
* Create a jwt with the EPerson details in it * Create a jwt with the EPerson details in it
* @param context * @param context
* @param request * @param request
* @param ePerson * @param detachedEPerson
* @param groups * @param groups
* @return * @return
* @throws JOSEException * @throws JOSEException
*/ */
public String createTokenForEPerson(Context context, HttpServletRequest request, EPerson ePerson, List<Group> groups) throws JOSEException { public String createTokenForEPerson(Context context, HttpServletRequest request, EPerson detachedEPerson, List<Group> groups) throws JOSEException {
createNewSessionSalt(ePerson);
context.setCurrentUser(ePerson); //This has to be set before createNewSessionSalt, otherwise authorizeException is thrown
context.setCurrentUser(detachedEPerson);
EPerson ePerson = createNewSessionSalt(context, detachedEPerson);
JWSSigner signer = new MACSigner(buildSigningKey(request, ePerson)); JWSSigner signer = new MACSigner(buildSigningKey(request, ePerson));
try {
context.commit();
} catch (SQLException e) {
//TODO FREDERIC throw exception and fail fast
log.error("Error while committing salt to eperson", e);
}
JWTClaimsSet.Builder builder = new JWTClaimsSet.Builder(); JWTClaimsSet.Builder builder = new JWTClaimsSet.Builder();
for (JWTClaimProvider jwtClaimProvider: jwtClaimProviders) { for (JWTClaimProvider jwtClaimProvider: jwtClaimProviders) {
@@ -182,10 +183,35 @@ public class JWTTokenHandler {
return ipAddress; return ipAddress;
} }
private void createNewSessionSalt(EPerson ePerson) { private EPerson createNewSessionSalt(Context context, EPerson detached) {
EPerson ePerson = null;
try {
//Reloading doesn't seem to work
// ePerson = context.reloadEntity(detached);
//This does work, even still has the previousActive
ePerson = ePersonService.find(context, detached.getID());
} catch (SQLException e) {
e.printStackTrace();
}
if (detached.getLastActive().getTime() - detached.getPreviousActive().getTime() > expirationTime) {
StringKeyGenerator stringKeyGenerator = KeyGenerators.string(); StringKeyGenerator stringKeyGenerator = KeyGenerators.string();
String salt = stringKeyGenerator.generateKey(); String salt = stringKeyGenerator.generateKey();
ePerson.setSessionSalt(salt); ePerson.setSessionSalt(salt);
try {
ePersonService.update(context, ePerson);
context.commit();
} catch (SQLException e) {
e.printStackTrace();
} catch (AuthorizeException e) {
e.printStackTrace();
}
}
return ePerson;
} }
public List<JWTClaimProvider> getJwtClaimProviders() { public List<JWTClaimProvider> getJwtClaimProviders() {

View File

@@ -55,10 +55,10 @@ public class JWTTokenRestAuthenticationServiceImpl implements RestAuthentication
} }
@Override @Override
public void addAuthenticationDataForUser(HttpServletRequest request, HttpServletResponse response, String email) { public void addAuthenticationDataForUser(HttpServletRequest request, HttpServletResponse response, EPerson ePerson) {
try { try {
Context context = ContextUtil.obtainContext(request); Context context = ContextUtil.obtainContext(request);
EPerson ePerson = ePersonService.findByEmail(context, email); // EPerson ePerson = ePersonService.findByEmail(context, email);
List<Group> groups = authenticationService.getSpecialGroups(context, request); List<Group> groups = authenticationService.getSpecialGroups(context, request);
String token = jwtTokenHandler.createTokenForEPerson(context, request, ePerson, groups); String token = jwtTokenHandler.createTokenForEPerson(context, request, ePerson, groups);

View File

@@ -20,7 +20,7 @@ import javax.servlet.http.HttpServletResponse;
@Service @Service
public interface RestAuthenticationService { public interface RestAuthenticationService {
void addAuthenticationDataForUser(HttpServletRequest request, HttpServletResponse response, String email); void addAuthenticationDataForUser(HttpServletRequest request, HttpServletResponse response, EPerson ePerson);
EPerson getAuthenticatedEPerson(HttpServletRequest request, Context context); EPerson getAuthenticatedEPerson(HttpServletRequest request, Context context);

View File

@@ -7,8 +7,6 @@
*/ */
package org.dspace.app.rest.security; package org.dspace.app.rest.security;
import org.dspace.app.rest.utils.ContextUtil;
import org.dspace.core.Context;
import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.Authentication; import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException; import org.springframework.security.core.AuthenticationException;
@@ -57,6 +55,7 @@ public class StatelessLoginFilter extends AbstractAuthenticationProcessingFilter
Authentication auth) throws IOException, ServletException { Authentication auth) throws IOException, ServletException {
//TODO every time we log in a new token and salt is created, might need to change this //TODO every time we log in a new token and salt is created, might need to change this
restAuthenticationService.addAuthenticationDataForUser(req, res, auth.getName()); DSpaceAuthentication dSpaceAuthentication = (DSpaceAuthentication) auth;
restAuthenticationService.addAuthenticationDataForUser(req, res, dSpaceAuthentication.getEPerson());
} }
} }

View File

@@ -53,4 +53,4 @@ plugin.sequence.org.dspace.authenticate.AuthenticationMethod = org.dspace.authen
# Partial key that is used to sign the authentication tokens # Partial key that is used to sign the authentication tokens
jwt.token.secret = thisisatestsecretkeyforjwttokens jwt.token.secret = thisisatestsecretkeyforjwttokens
# Expiration time of a token in minutes # Expiration time of a token in minutes
jwt.token.expiration = 30 jwt.token.expiration = 1