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
protected transient EPersonService ePersonService;
@Transient
private Date previousActive;
/**
* Protected constructor, create object using:
* {@link org.dspace.eperson.service.EPersonService#create(Context)}
@@ -373,6 +376,7 @@ public class EPerson extends DSpaceObject implements DSpaceObjectLegacySupport
*/
public void setLastActive(Date when)
{
this.previousActive = lastActive;
this.lastActive = when;
}
@@ -444,4 +448,12 @@ public class EPerson extends DSpaceObject implements DSpaceObjectLegacySupport
public void setSessionSalt(String 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;
import java.util.Collection;
import java.util.List;
import org.dspace.eperson.EPerson;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import java.util.Collection;
import java.util.List;
public class DSpaceAuthentication implements Authentication {
private EPerson ePerson;
private String username;
private String password;
private List<GrantedAuthority> authorities;
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) {
this.username = username;
this.password = password;
@@ -57,4 +67,8 @@ public class DSpaceAuthentication implements Authentication {
public String getName() {
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
requestService.setCurrentUserId(ePerson.getID());
return new DSpaceAuthentication(ePerson.getEmail(), password, getGrantedAuthorities(context, ePerson));
return new DSpaceAuthentication(ePerson, getGrantedAuthorities(context, ePerson));
} else {
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.util.DateUtils;
import org.apache.commons.lang3.StringUtils;
import org.dspace.authorize.AuthorizeException;
import org.dspace.core.Context;
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.servicemanager.config.DSpaceConfigurationService;
import org.dspace.services.ConfigurationService;
@@ -59,6 +61,9 @@ public class JWTTokenHandler {
@Autowired
private EPersonClaimProvider ePersonClaimProvider;
@Autowired
private EPersonService ePersonService;
public JWTTokenHandler() {
//TODO move properties to authentication module
@@ -118,25 +123,21 @@ public class JWTTokenHandler {
* Create a jwt with the EPerson details in it
* @param context
* @param request
* @param ePerson
* @param detachedEPerson
* @param groups
* @return
* @throws JOSEException
*/
public String createTokenForEPerson(Context context, HttpServletRequest request, EPerson ePerson, List<Group> groups) throws JOSEException {
createNewSessionSalt(ePerson);
context.setCurrentUser(ePerson);
public String createTokenForEPerson(Context context, HttpServletRequest request, EPerson detachedEPerson, List<Group> groups) throws JOSEException {
//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));
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();
for (JWTClaimProvider jwtClaimProvider: jwtClaimProviders) {
@@ -182,10 +183,35 @@ public class JWTTokenHandler {
return ipAddress;
}
private void createNewSessionSalt(EPerson ePerson) {
StringKeyGenerator stringKeyGenerator = KeyGenerators.string();
String salt = stringKeyGenerator.generateKey();
ePerson.setSessionSalt(salt);
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();
String salt = stringKeyGenerator.generateKey();
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() {

View File

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

View File

@@ -20,7 +20,7 @@ import javax.servlet.http.HttpServletResponse;
@Service
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);

View File

@@ -7,8 +7,6 @@
*/
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.core.Authentication;
import org.springframework.security.core.AuthenticationException;
@@ -57,6 +55,7 @@ public class StatelessLoginFilter extends AbstractAuthenticationProcessingFilter
Authentication auth) throws IOException, ServletException {
//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
jwt.token.secret = thisisatestsecretkeyforjwttokens
# Expiration time of a token in minutes
jwt.token.expiration = 30
jwt.token.expiration = 1