diff --git a/src/main/java/com/porterhead/rest/authorization/UserSession.java b/src/main/java/com/porterhead/rest/authorization/UserSession.java deleted file mode 100644 index 0d3c8d2..0000000 --- a/src/main/java/com/porterhead/rest/authorization/UserSession.java +++ /dev/null @@ -1,53 +0,0 @@ -package com.porterhead.rest.authorization; - -import com.porterhead.rest.user.domain.SessionToken; - -import javax.persistence.Cacheable; -import java.io.Serializable; -import java.util.Date; - -/** - * Cacheable Object that holds information on the User and their session status - * - * - * @author: Iain Porter - */ -@Cacheable -public class UserSession implements Serializable { - - private Date createTime; - - private Date lastUpdated; - - private String sessionToken; - - private boolean authenticationFailure = false; - - public UserSession(){} - - public UserSession(SessionToken token) { - this.createTime = token.getTimeCreated(); - this.lastUpdated = token.getLastUpdated(); - this.sessionToken = token.getToken(); - } - - public Date getCreateTime() { - return createTime; - } - - public Date getLastUpdated() { - return lastUpdated; - } - - public String getSessionToken() { - return sessionToken; - } - - public boolean isAuthenticationFailure() { - return authenticationFailure; - } - - public void setAuthenticationFailure(boolean authenticationFailure) { - this.authenticationFailure = authenticationFailure; - } -} diff --git a/src/main/java/com/porterhead/rest/authorization/impl/RequestSigningAuthorizationService.java b/src/main/java/com/porterhead/rest/authorization/impl/RequestSigningAuthorizationService.java index 6000b84..a0ff3a4 100644 --- a/src/main/java/com/porterhead/rest/authorization/impl/RequestSigningAuthorizationService.java +++ b/src/main/java/com/porterhead/rest/authorization/impl/RequestSigningAuthorizationService.java @@ -9,7 +9,7 @@ import com.porterhead.rest.user.UserRepository; import com.porterhead.rest.user.UserService; import com.porterhead.rest.user.api.ExternalUser; -import com.porterhead.rest.user.domain.SessionToken; +import com.porterhead.rest.user.domain.AuthorizationToken; import com.porterhead.rest.user.domain.User; import com.porterhead.rest.user.exception.AuthorizationException; import com.porterhead.rest.util.DateUtil; @@ -169,16 +169,11 @@ private boolean isAuthorized(User user, AuthorizationRequestContext authorizatio Assert.notNull(user); Assert.notNull(authorizationRequest.getAuthorizationToken()); String unEncodedString = composeUnEncodedRequest(authorizationRequest); - Set sessionTokens = user.getSessions(); - String userTokenHash = null; - for (SessionToken token : sessionTokens) { - userTokenHash = encodeAuthToken(token.getToken(), unEncodedString); + AuthorizationToken authorizationToken = user.getAuthorizationToken(); + String userTokenHash = encodeAuthToken(authorizationToken.getToken(), unEncodedString); if (hashedToken.equals(userTokenHash)) { - token.setLastUpdated(new Date()); - userRepository.save(user); return true; } - } LOG.error("Hash check failed for hashed token: {} for the following request: {} for user: {}", new Object[]{authorizationRequest.getAuthorizationToken(), unEncodedString, user.getId()}); return false; diff --git a/src/main/java/com/porterhead/rest/authorization/impl/SessionTokenAuthorizationService.java b/src/main/java/com/porterhead/rest/authorization/impl/SessionTokenAuthorizationService.java index b733e79..061aa5b 100644 --- a/src/main/java/com/porterhead/rest/authorization/impl/SessionTokenAuthorizationService.java +++ b/src/main/java/com/porterhead/rest/authorization/impl/SessionTokenAuthorizationService.java @@ -4,7 +4,7 @@ import com.porterhead.rest.authorization.AuthorizationService; import com.porterhead.rest.user.UserRepository; import com.porterhead.rest.user.api.ExternalUser; -import com.porterhead.rest.user.domain.SessionToken; +import com.porterhead.rest.user.domain.AuthorizationToken; import com.porterhead.rest.user.domain.User; import com.porterhead.rest.user.exception.AuthorizationException; @@ -40,13 +40,10 @@ public ExternalUser authorize(AuthorizationRequestContext securityContext) { if(user == null) { throw new AuthorizationException("Session token not valid"); } - for (SessionToken sessionToken : user.getSessions()) { - if (sessionToken.getToken().equals(token)) { - sessionToken.setLastUpdated(new Date()); - userRepository.save(user); + AuthorizationToken authorizationToken = user.getAuthorizationToken(); + if (authorizationToken.getToken().equals(token)) { externalUser = new ExternalUser(user); } - } return externalUser; } } diff --git a/src/main/java/com/porterhead/rest/config/ApplicationConfig.java b/src/main/java/com/porterhead/rest/config/ApplicationConfig.java index 3c9022a..84f1528 100644 --- a/src/main/java/com/porterhead/rest/config/ApplicationConfig.java +++ b/src/main/java/com/porterhead/rest/config/ApplicationConfig.java @@ -17,7 +17,7 @@ public class ApplicationConfig { private final static String HOSTNAME_PROPERTY = "hostNameUrl"; private final static String SECURITY_AUTHORIZATION_REQUIRE_SIGNED_REQUESTS = "security.authorization.requireSignedRequests"; - private final static String SESSION_EXPIRY_DURATION = "session.timeToLive.inMinutes"; + private final static String AUTHORIZATION_EXPIRY_DURATION = "authorization.timeToLive.inSeconds"; private final static String SESSION_DATE_OFFSET_IN_MINUTES = "session.date.offset.inMinutes"; private final static String TOKEN_EMAIL_REGISTRATION_DURATION = "token.emailRegistration.timeToLive.inMinutes"; private final static String TOKEN_EMAIL_VERIFICATION_DURATION = "token.emailVerification.timeToLive.inMinutes"; @@ -44,8 +44,8 @@ public String getFacebookClientSecret() { return environment.getProperty("facebook.clientSecret"); } - public int getSessionExpiryTimeInMinutes() { - return Integer.parseInt(environment.getProperty(SESSION_EXPIRY_DURATION)); + public int getAuthorizationExpiryTimeInSeconds() { + return Integer.parseInt(environment.getProperty(AUTHORIZATION_EXPIRY_DURATION)); } public int getSessionDateOffsetInMinutes() { diff --git a/src/main/java/com/porterhead/rest/user/SessionReaper.java b/src/main/java/com/porterhead/rest/user/SessionReaper.java deleted file mode 100644 index b5d1634..0000000 --- a/src/main/java/com/porterhead/rest/user/SessionReaper.java +++ /dev/null @@ -1,36 +0,0 @@ -package com.porterhead.rest.user; - -import com.porterhead.rest.config.ApplicationConfig; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; - -/** - * - * @version 1.0 - * @author: Iain Porter iain.porter@porterhead.com - * @since 11/01/2013 - */ -public class SessionReaper { - - Logger LOG = LoggerFactory.getLogger(SessionReaper.class); - - private UserService userService; - - ApplicationConfig config; - - public void cleanUpExpiredSessions() { - Integer sessionCount = userService.deleteExpiredSessions(config.getSessionExpiryTimeInMinutes()); - LOG.debug("Session reaper has removed {} expired sessions", sessionCount); - } - - @Autowired - public void setConfig(ApplicationConfig config) { - this.config = config; - } - - @Autowired - public void setUserService(UserService userService) { - this.userService = userService; - } -} diff --git a/src/main/java/com/porterhead/rest/user/UserRepository.java b/src/main/java/com/porterhead/rest/user/UserRepository.java index 7cffe45..58782ab 100644 --- a/src/main/java/com/porterhead/rest/user/UserRepository.java +++ b/src/main/java/com/porterhead/rest/user/UserRepository.java @@ -20,10 +20,10 @@ public interface UserRepository extends JpaRepository { @Query("select u from User u where uuid = ?") User findByUuid(String uuid); - @Query("select u from User u where u in (select user from SessionToken where lastUpdated < ?)") + @Query("select u from User u where u in (select user from AuthorizationToken where lastUpdated < ?)") List findByExpiredSession(Date lastUpdated); - @Query("select u from User u where u = (select user from SessionToken where token = ?)") + @Query("select u from User u where u = (select user from AuthorizationToken where token = ?)") User findBySession(String token); } diff --git a/src/main/java/com/porterhead/rest/user/UserService.java b/src/main/java/com/porterhead/rest/user/UserService.java index 400b433..98aa741 100644 --- a/src/main/java/com/porterhead/rest/user/UserService.java +++ b/src/main/java/com/porterhead/rest/user/UserService.java @@ -1,7 +1,9 @@ package com.porterhead.rest.user; import com.porterhead.rest.user.api.*; +import com.porterhead.rest.user.domain.AuthorizationToken; import com.porterhead.rest.user.domain.Role; +import com.porterhead.rest.user.domain.User; import org.springframework.social.connect.Connection; /** @@ -74,11 +76,11 @@ public interface UserService { public ExternalUser saveUser(String userId, UpdateUserRequest request); /** - * Delete all SessionToken objects that have not been accessed within the duration specified by the argument timeSinceLastUpdatedInMinutes + * Create an AuthorizationToken for the User * - * @param timeSinceLastUpdatedInMinutes - * @return the number of sessions removed + * @return */ - public Integer deleteExpiredSessions(int timeSinceLastUpdatedInMinutes); + public AuthorizationToken createAuthorizationToken(User user); + } diff --git a/src/main/java/com/porterhead/rest/user/UserServiceImpl.java b/src/main/java/com/porterhead/rest/user/UserServiceImpl.java index 602146a..b13392f 100644 --- a/src/main/java/com/porterhead/rest/user/UserServiceImpl.java +++ b/src/main/java/com/porterhead/rest/user/UserServiceImpl.java @@ -1,8 +1,10 @@ package com.porterhead.rest.user; +import com.porterhead.rest.config.ApplicationConfig; import com.porterhead.rest.service.BaseService; import com.porterhead.rest.user.api.*; +import com.porterhead.rest.user.domain.AuthorizationToken; import com.porterhead.rest.user.domain.Role; import com.porterhead.rest.user.domain.User; import com.porterhead.rest.user.exception.AuthenticationException; @@ -11,7 +13,6 @@ import com.porterhead.rest.user.exception.UserNotFoundException; import com.porterhead.rest.user.social.JpaUsersConnectionRepository; import com.porterhead.rest.util.StringUtil; -import org.joda.time.DateTime; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -40,15 +41,19 @@ public class UserServiceImpl extends BaseService implements UserService { private UserRepository userRepository; + private ApplicationConfig applicationConfig; + public UserServiceImpl(Validator validator) { super(validator); } @Autowired - public UserServiceImpl(UsersConnectionRepository usersConnectionRepository, Validator validator) { + public UserServiceImpl(UsersConnectionRepository usersConnectionRepository, + Validator validator, ApplicationConfig applicationConfig) { this(validator); this.jpaUsersConnectionRepository = usersConnectionRepository; ((JpaUsersConnectionRepository)this.jpaUsersConnectionRepository).setUserService(this); + this.applicationConfig = applicationConfig; } private static final Logger LOG = LoggerFactory.getLogger(UserServiceImpl.class); @@ -59,7 +64,7 @@ public UserServiceImpl(UsersConnectionRepository usersConnectionRepository, Vali * This method creates a User with the given Role. A check is made to see if the username already exists and a duplication * check is made on the email address if it is present in the request. *

- * The password is hashed and a SessionToken generated for subsequent authorization of role-protected requests. + * The password is hashed and a AuthorizationToken generated for subsequent authorization of role-protected requests. * */ @Transactional @@ -71,7 +76,7 @@ public AuthenticatedUserToken createUser(CreateUserRequest request, Role role) { } User newUser = createNewUser(request, role); - AuthenticatedUserToken token = new AuthenticatedUserToken(newUser.getUuid().toString(), newUser.addSessionToken().getToken()); + AuthenticatedUserToken token = new AuthenticatedUserToken(newUser.getUuid().toString(), createAuthorizationToken(newUser).getToken()); userRepository.save(newUser); return token; } @@ -80,7 +85,8 @@ public AuthenticatedUserToken createUser(CreateUserRequest request, Role role) { public AuthenticatedUserToken createUser(Role role) { User user = new User(); user.setRole(role); - AuthenticatedUserToken token = new AuthenticatedUserToken(user.getUuid().toString(), user.addSessionToken().getToken()); + AuthenticatedUserToken token = new AuthenticatedUserToken(user.getUuid().toString(), + createAuthorizationToken(user).getToken()); userRepository.save(user); return token; } @@ -107,7 +113,7 @@ public AuthenticatedUserToken login(LoginRequest request) { throw new AuthenticationException(); } if (hashedPassword.equals(user.getHashedPassword())) { - return new AuthenticatedUserToken(user.getUuid().toString(), user.addSessionToken().getToken()); + return new AuthenticatedUserToken(user.getUuid().toString(), createAuthorizationToken(user).getToken()); } else { throw new AuthenticationException(); } @@ -121,7 +127,7 @@ public AuthenticatedUserToken login(LoginRequest request) { * *

* - * A SessionToken is generated and any Profile data that can be collected from the Social account is propagated to the User object. + * A AuthorizationToken is generated and any Profile data that can be collected from the Social account is propagated to the User object. * */ @Transactional @@ -136,7 +142,7 @@ public AuthenticatedUserToken socialLogin(Connection connection) { throw new AuthenticationException(); } updateUserFromProfile(connection, user); - return new AuthenticatedUserToken(user.getUuid().toString(), user.addSessionToken().getToken()); + return new AuthenticatedUserToken(user.getUuid().toString(), createAuthorizationToken(user).getToken()); } /** @@ -190,19 +196,12 @@ public ExternalUser saveUser(String userId, UpdateUserRequest request) { return new ExternalUser(user); } - @Transactional - public Integer deleteExpiredSessions(int timeSinceLastUpdatedInMinutes) { - DateTime date = new DateTime(); - date = date.minusMinutes(timeSinceLastUpdatedInMinutes); - List expiredUserSessions = userRepository.findByExpiredSession(date.toDate()); - int count = expiredUserSessions.size(); - for(User user : expiredUserSessions) { - user.removeExpiredSessions(date.toDate()); - } - if(count > 0) { - userRepository.save(expiredUserSessions); - } - return count; + @Override + public AuthorizationToken createAuthorizationToken(User user) { + if(user.getAuthorizationToken() == null || user.getAuthorizationToken().hasExpired()) { + user.setAuthorizationToken(new AuthorizationToken(user, applicationConfig.getAuthorizationExpiryTimeInSeconds())); + } + return user.getAuthorizationToken(); } private User createNewUser(CreateUserRequest request, Role role) { diff --git a/src/main/java/com/porterhead/rest/user/api/ExternalUser.java b/src/main/java/com/porterhead/rest/user/api/ExternalUser.java index 6b47dac..a7cd5a8 100644 --- a/src/main/java/com/porterhead/rest/user/api/ExternalUser.java +++ b/src/main/java/com/porterhead/rest/user/api/ExternalUser.java @@ -1,6 +1,6 @@ package com.porterhead.rest.user.api; -import com.porterhead.rest.user.domain.SessionToken; +import com.porterhead.rest.user.domain.AuthorizationToken; import com.porterhead.rest.user.domain.SocialUser; import com.porterhead.rest.user.domain.User; import org.codehaus.jackson.annotate.JsonIgnore; @@ -64,7 +64,7 @@ public ExternalUser(User user) { role = user.getRole().toString(); } - public ExternalUser(User user, SessionToken activeSession) { + public ExternalUser(User user, AuthorizationToken activeSession) { this(user); } diff --git a/src/main/java/com/porterhead/rest/user/domain/SessionToken.java b/src/main/java/com/porterhead/rest/user/domain/AuthorizationToken.java similarity index 51% rename from src/main/java/com/porterhead/rest/user/domain/SessionToken.java rename to src/main/java/com/porterhead/rest/user/domain/AuthorizationToken.java index 3a8a30a..0d78085 100644 --- a/src/main/java/com/porterhead/rest/user/domain/SessionToken.java +++ b/src/main/java/com/porterhead/rest/user/domain/AuthorizationToken.java @@ -13,27 +13,37 @@ * @since 28/12/2012 */ @Entity -@Table(name="rest_session_token") -public class SessionToken extends AbstractPersistable implements Comparable{ +@Table(name="rest_authorization_token") +public class AuthorizationToken extends AbstractPersistable { + + private final static Integer DEFAULT_TIME_TO_LIVE_IN_SECONDS = (60 * 60 * 24 * 30); //30 Days @Column(length=36) private String token; private Date timeCreated; - private Date lastUpdated; + private Date expirationDate; - @ManyToOne @JoinColumn(name = "user_id") + @OneToOne(fetch = FetchType.LAZY) private User user; - public SessionToken() {} + public AuthorizationToken() {} + + public AuthorizationToken(User user) { + this(user, DEFAULT_TIME_TO_LIVE_IN_SECONDS); + } - public SessionToken(User user) { + public AuthorizationToken(User user, Integer timeToLiveInSeconds) { this.token = UUID.randomUUID().toString(); this.user = user; this.timeCreated = new Date(); - this.lastUpdated = new Date(); + this.expirationDate = new Date(System.currentTimeMillis() + (timeToLiveInSeconds * 1000L)); + } + + public boolean hasExpired() { + return this.expirationDate != null && this.expirationDate.before(new Date()); } public String getToken() { @@ -47,16 +57,4 @@ public User getUser() { public Date getTimeCreated() { return timeCreated; } - - public int compareTo(SessionToken userSession) { - return this.lastUpdated.compareTo(userSession.getLastUpdated()); - } - - public Date getLastUpdated() { - return lastUpdated; - } - - public void setLastUpdated(Date lastUpdated) { - this.lastUpdated = lastUpdated; - } } diff --git a/src/main/java/com/porterhead/rest/user/domain/User.java b/src/main/java/com/porterhead/rest/user/domain/User.java index 3cb1189..b0870bc 100644 --- a/src/main/java/com/porterhead/rest/user/domain/User.java +++ b/src/main/java/com/porterhead/rest/user/domain/User.java @@ -1,13 +1,10 @@ package com.porterhead.rest.user.domain; -import com.porterhead.rest.authorization.UserSession; import com.porterhead.rest.model.BaseEntity; import com.porterhead.rest.user.api.ExternalUser; import com.porterhead.rest.util.HashUtil; import org.hibernate.annotations.LazyCollection; import org.hibernate.annotations.LazyCollectionOption; -import org.hibernate.annotations.Sort; -import org.hibernate.annotations.SortType; import org.springframework.util.StringUtils; import javax.persistence.*; @@ -49,12 +46,10 @@ public class User extends BaseEntity { @LazyCollection(LazyCollectionOption.FALSE) private List verificationTokens = new ArrayList(); - @OneToMany(mappedBy="user", - targetEntity=SessionToken.class, - cascade= CascadeType.ALL, orphanRemoval = true) - @LazyCollection(LazyCollectionOption.FALSE) - @Sort(type = SortType.NATURAL) - private SortedSet sessions = Collections.synchronizedSortedSet(new TreeSet(Collections.reverseOrder())); + @OneToOne(fetch = FetchType.LAZY, + mappedBy = "user", + cascade = CascadeType.ALL) + private AuthorizationToken authorizationToken; public User() { this(UUID.randomUUID()); @@ -167,20 +162,14 @@ public synchronized List getVerificationTokens() { return Collections.unmodifiableList(this.verificationTokens); } - public SessionToken addSessionToken() { - SessionToken token = new SessionToken(this); - this.sessions.add(token); - return token; - } + public synchronized void setAuthorizationToken(AuthorizationToken token) { - public SortedSet getSessions() { - SortedSet copySet = new TreeSet(Collections.reverseOrder()); - copySet.addAll(this.sessions); - return Collections.unmodifiableSortedSet(copySet); + + this.authorizationToken = token; } - public void removeSession(SessionToken session) { - this.sessions.remove(session); + public synchronized AuthorizationToken getAuthorizationToken() { + return authorizationToken; } /** @@ -233,22 +222,6 @@ public void setVerified(boolean verified) { isVerified = verified; } - public void setActiveSession(UserSession session) { - for(SessionToken token : getSessions()) { - if(token.getToken().equals(session.getSessionToken())) { - token.setLastUpdated(new Date()); - } - } - } - - public void removeExpiredSessions(Date expiryDate) { - for(SessionToken token : getSessions()) { - if(token.getLastUpdated().before(expiryDate)) { - removeSession(token); - } - } - } - /** * Hash the password using salt values * See https://www.owasp.org/index.php/Hashing_Java diff --git a/src/main/resources/META-INF/persistence.xml b/src/main/resources/META-INF/persistence.xml index 757e98c..a65a74e 100644 --- a/src/main/resources/META-INF/persistence.xml +++ b/src/main/resources/META-INF/persistence.xml @@ -6,7 +6,7 @@ org.hibernate.ejb.HibernatePersistence com.porterhead.rest.user.domain.User com.porterhead.rest.user.domain.SocialUser - com.porterhead.rest.user.domain.SessionToken + com.porterhead.rest.user.domain.AuthorizationToken com.porterhead.rest.user.domain.VerificationToken diff --git a/src/main/resources/META-INF/spring/data-context.xml b/src/main/resources/META-INF/spring/data-context.xml index 19a188a..be57c9a 100644 --- a/src/main/resources/META-INF/spring/data-context.xml +++ b/src/main/resources/META-INF/spring/data-context.xml @@ -56,7 +56,7 @@ - + diff --git a/src/main/resources/META-INF/spring/root-context.xml b/src/main/resources/META-INF/spring/root-context.xml index 6144a3e..8029b19 100644 --- a/src/main/resources/META-INF/spring/root-context.xml +++ b/src/main/resources/META-INF/spring/root-context.xml @@ -16,10 +16,4 @@ - - - - - - \ No newline at end of file diff --git a/src/main/resources/properties/app.properties b/src/main/resources/properties/app.properties index ce5ecaf..b20b414 100644 --- a/src/main/resources/properties/app.properties +++ b/src/main/resources/properties/app.properties @@ -10,9 +10,8 @@ security.encryptSalt=45ea2b40ef910eef32 #See com.porterheadead.rest.authorization.impl.RequestSigningAuthorizationService security.authorization.requireSignedRequests=true -#How long in minutes before removing inactive session tokens -#See com.porterheadead.rest.user.SessionReaper -session.timeToLive.inMinutes=120 +#How long in seconds before authorizationToken expires +authorization.timeToLive.inSeconds=2592000 #How long in minutes to allow the request timestamp to differ from the server time session.date.offset.inMinutes=15 diff --git a/src/test/java/com/porterhead/rest/authorization/BaseAuthorizationTst.java b/src/test/java/com/porterhead/rest/authorization/BaseAuthorizationTst.java index 9b8462d..f2c3ac0 100644 --- a/src/test/java/com/porterhead/rest/authorization/BaseAuthorizationTst.java +++ b/src/test/java/com/porterhead/rest/authorization/BaseAuthorizationTst.java @@ -3,6 +3,7 @@ import com.porterhead.rest.authorization.impl.SessionTokenAuthorizationService; import com.porterhead.rest.config.ApplicationConfig; import com.porterhead.rest.user.UserRepository; +import com.porterhead.rest.user.domain.AuthorizationToken; import com.porterhead.rest.user.domain.User; import com.porterhead.rest.util.DateUtil; import org.junit.Before; @@ -18,11 +19,11 @@ */ public class BaseAuthorizationTst { - protected static String SESSION_TOKEN; + protected static String AUTH_TOKEN; protected static final User USER = new User(); { - USER.addSessionToken(); - SESSION_TOKEN = USER.getSessions().first().getToken(); + USER.setAuthorizationToken(new AuthorizationToken(USER)); + AUTH_TOKEN = USER.getAuthorizationToken().getToken(); } protected AuthorizationService authorizationService; @@ -33,7 +34,7 @@ public class BaseAuthorizationTst { public void setUp() { userRepository = mock(UserRepository.class); when(userRepository.findByUuid(eq(USER.getUuid().toString()))).thenReturn(USER); - when(userRepository.findBySession(eq(SESSION_TOKEN))).thenReturn(USER); + when(userRepository.findBySession(eq(AUTH_TOKEN))).thenReturn(USER); applicationConfig = mock(ApplicationConfig.class); when(applicationConfig.getSessionDateOffsetInMinutes()).thenReturn(30); authorizationService = new SessionTokenAuthorizationService(userRepository); diff --git a/src/test/java/com/porterhead/rest/authorization/RequestSigningAuthorizationServiceTest.java b/src/test/java/com/porterhead/rest/authorization/RequestSigningAuthorizationServiceTest.java index 2ce6378..7328623 100644 --- a/src/test/java/com/porterhead/rest/authorization/RequestSigningAuthorizationServiceTest.java +++ b/src/test/java/com/porterhead/rest/authorization/RequestSigningAuthorizationServiceTest.java @@ -37,14 +37,14 @@ public void setUp() { @Test public void authorizeUser() throws Exception { String dateString = DateUtil.getCurrentDateAsIso8061String(); - String hashedToken = new String(Base64.encodeBase64(DigestUtils.sha256(USER.getSessions().first().getToken() + ":user/555,POST," + dateString + ",123"))); + String hashedToken = new String(Base64.encodeBase64(DigestUtils.sha256(USER.getAuthorizationToken().getToken() + ":user/555,POST," + dateString + ",123"))); ExternalUser user = authorizationService.authorize(getAuthorizationRequest(USER.getUuid().toString() + ":" + hashedToken, "user/555", dateString, "123")); assertThat(user.getId(), is(USER.getUuid().toString())); } @Test (expected = AuthorizationException.class) public void invalidUnEncodedRequest() { - String hashedToken = new String(Base64.encodeBase64(DigestUtils.sha256(SESSION_TOKEN + ":hash123,123"))); + String hashedToken = new String(Base64.encodeBase64(DigestUtils.sha256(AUTH_TOKEN + ":hash123,123"))); authorizationService.authorize(getAuthorizationRequest(USER.getUuid().toString() + ":" + hashedToken, "hash123,1234", "123")); } @@ -64,7 +64,7 @@ public void missingNonce() { @Test (expected = AuthorizationException.class) public void wrongNonce() { String dateString = DateUtil.getCurrentDateAsIso8061String(); - String hashedToken = new String(Base64.encodeBase64(DigestUtils.sha256(USER.getSessions().first().getToken() + ":hash123,123,POST," + dateString + ",123"))); + String hashedToken = new String(Base64.encodeBase64(DigestUtils.sha256(USER.getAuthorizationToken().getToken() + ":hash123,123,POST," + dateString + ",123"))); authorizationService.authorize(getAuthorizationRequest(USER.getUuid().toString() + ":" + hashedToken, "hash123,123", dateString, "567")); } @@ -72,7 +72,7 @@ public void wrongNonce() { public void dateOutOfRange() { when(applicationConfig.getSessionDateOffsetInMinutes()).thenReturn(5); String dateString = DateUtil.getDateDateAsIso8061String(new DateTime().minusMinutes(20)); - String hashedToken = new String(Base64.encodeBase64(DigestUtils.sha256(USER.getSessions().first().getToken() + ":hash123,123,POST," + dateString + ",123"))); + String hashedToken = new String(Base64.encodeBase64(DigestUtils.sha256(USER.getAuthorizationToken().getToken() + ":hash123,123,POST," + dateString + ",123"))); authorizationService.authorize(getAuthorizationRequest(USER.getUuid().toString() + ":" + hashedToken, "hash123,123", dateString, "567")); } diff --git a/src/test/java/com/porterhead/rest/authorization/SessionTokenAuthorizationServiceTest.java b/src/test/java/com/porterhead/rest/authorization/SessionTokenAuthorizationServiceTest.java index b714c18..9075fd8 100644 --- a/src/test/java/com/porterhead/rest/authorization/SessionTokenAuthorizationServiceTest.java +++ b/src/test/java/com/porterhead/rest/authorization/SessionTokenAuthorizationServiceTest.java @@ -26,8 +26,7 @@ public void setUp() { @Test public void authorizeUser() throws Exception { - String sessionToken = "123456789"; - ExternalUser user = authorizationService.authorize(getAuthorizationRequest(SESSION_TOKEN, "user/123", null)); + ExternalUser user = authorizationService.authorize(getAuthorizationRequest(AUTH_TOKEN, "user/123", null)); assertThat(user.getId(), is(USER.getUuid().toString())); } diff --git a/src/test/java/com/porterhead/rest/filter/SecurityContextFilterTest.java b/src/test/java/com/porterhead/rest/filter/SecurityContextFilterTest.java index ee2ea7d..d291259 100644 --- a/src/test/java/com/porterhead/rest/filter/SecurityContextFilterTest.java +++ b/src/test/java/com/porterhead/rest/filter/SecurityContextFilterTest.java @@ -4,6 +4,7 @@ import com.porterhead.rest.user.UserRepository; import com.porterhead.rest.user.UserService; import com.porterhead.rest.user.api.ExternalUser; +import com.porterhead.rest.user.domain.AuthorizationToken; import com.porterhead.rest.user.domain.User; import com.porterhead.rest.user.exception.AuthorizationException; import com.sun.jersey.spi.container.ContainerRequest; @@ -61,10 +62,10 @@ public void validAuthHeaders() { private void setUpValidRequest() { User user = new User(); - user.addSessionToken(); + user.setAuthorizationToken(new AuthorizationToken(user)); final ExternalUser externalUser = new ExternalUser(user); String dateString = new DateTime().toString(ISODateTimeFormat.dateTimeNoMillis()); - String hashedToken = new String(Base64.encodeBase64(DigestUtils.sha256(user.getSessions().first().getToken() + ":user/555,POST," + dateString + ",123"))); + String hashedToken = new String(Base64.encodeBase64(DigestUtils.sha256(user.getAuthorizationToken().getToken() + ":user/555,POST," + dateString + ",123"))); when(containerRequest.getHeaderValue(SecurityContextFilter.HEADER_AUTHORIZATION)).thenReturn(externalUser.getId() + ":" + hashedToken); when(containerRequest.getHeaderValue(SecurityContextFilter.HEADER_DATE)).thenReturn(dateString); when(containerRequest.getHeaderValue(SecurityContextFilter.HEADER_NONCE)).thenReturn("123"); diff --git a/src/test/java/com/porterhead/rest/resource/BaseResourceTst.java b/src/test/java/com/porterhead/rest/resource/BaseResourceTst.java index a66b040..a88b84a 100644 --- a/src/test/java/com/porterhead/rest/resource/BaseResourceTst.java +++ b/src/test/java/com/porterhead/rest/resource/BaseResourceTst.java @@ -8,7 +8,7 @@ import com.porterhead.rest.gateway.EmailServicesGateway; import com.porterhead.rest.mock.AppMockConfiguration; import com.porterhead.rest.user.domain.Role; -import com.porterhead.rest.user.domain.SessionToken; +import com.porterhead.rest.user.domain.AuthorizationToken; import com.porterhead.rest.user.api.CreateUserRequest; import com.porterhead.rest.user.api.UpdateUserRequest; import com.porterhead.rest.user.domain.User; @@ -54,10 +54,10 @@ public BaseResourceTst(WebAppDescriptor descriptor) { PASSWORD_REQUEST.setPassword(PASSWORD); } - protected static SessionToken ACTIVE_SESSION; + protected static AuthorizationToken AUTH_TOKEN; { - TEST_USER.addSessionToken(); - ACTIVE_SESSION = TEST_USER.getSessions().first(); + TEST_USER.setAuthorizationToken(new AuthorizationToken(TEST_USER)); + AUTH_TOKEN = TEST_USER.getAuthorizationToken(); } protected static ApplicationContext appCtx; diff --git a/src/test/java/com/porterhead/rest/user/SessionReaperTest.java b/src/test/java/com/porterhead/rest/user/SessionReaperTest.java deleted file mode 100644 index 18a73c1..0000000 --- a/src/test/java/com/porterhead/rest/user/SessionReaperTest.java +++ /dev/null @@ -1,68 +0,0 @@ -package com.porterhead.rest.user; - -import com.porterhead.rest.config.ApplicationConfig; -import com.porterhead.rest.user.api.AuthenticatedUserToken; -import com.porterhead.rest.user.api.CreateUserRequest; -import com.porterhead.rest.user.api.LoginRequest; -import com.porterhead.rest.user.domain.Role; -import com.porterhead.rest.user.domain.User; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.test.context.ActiveProfiles; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; -import org.springframework.transaction.annotation.Transactional; - -import static org.hamcrest.Matchers.is; -import static org.junit.Assert.assertThat; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -/** - * @version 1.0 - * @author: Iain Porter iain.porter@porterhead.com - * @since 26/01/2013 - */ -@RunWith(SpringJUnit4ClassRunner.class) -@ContextConfiguration("classpath:META-INF/spring/root-context.xml") -@ActiveProfiles(profiles = "dev") -@Transactional -public class SessionReaperTest extends BaseServiceTest { - - private SessionReaper sessionReaper; - ApplicationConfig config = mock(ApplicationConfig.class); - - @Before - public void setUp() { - sessionReaper = new SessionReaper(); - sessionReaper.setConfig(config); - sessionReaper.setUserService(userService); - } - - @Test - public void sessionsStillActive() { - when(config.getSessionExpiryTimeInMinutes()).thenReturn(1); - CreateUserRequest request = getDefaultCreateUserRequest(); - AuthenticatedUserToken userToken = userService.createUser(request, Role.authenticated); - LoginRequest loginRequest = new LoginRequest(); - loginRequest.setUsername(request.getUser().getEmailAddress()); - loginRequest.setPassword(request.getPassword().getPassword()); - userService.login(loginRequest); - userService.login(loginRequest); - sessionReaper.cleanUpExpiredSessions(); - User user = userRepository.findByUuid(userToken.getUserId()); - assertThat(user.getSessions().size(), is(3)); - } - - @Test - public void sessionHasBeenReaped() { - when(config.getSessionExpiryTimeInMinutes()).thenReturn(-1); - CreateUserRequest request = getDefaultCreateUserRequest(); - AuthenticatedUserToken userToken = userService.createUser(request, Role.authenticated); - sessionReaper.cleanUpExpiredSessions(); - User user = userRepository.findByUuid(userToken.getUserId()); - assertThat(user.getSessions().size(), is(0)); - } - -} diff --git a/src/test/java/com/porterhead/rest/user/UserServiceTest.java b/src/test/java/com/porterhead/rest/user/UserServiceTest.java index 67cec08..a691433 100644 --- a/src/test/java/com/porterhead/rest/user/UserServiceTest.java +++ b/src/test/java/com/porterhead/rest/user/UserServiceTest.java @@ -3,8 +3,8 @@ import com.porterhead.rest.exception.ValidationException; import com.porterhead.rest.user.api.*; import com.porterhead.rest.user.builder.ExternalUserBuilder; +import com.porterhead.rest.user.domain.AuthorizationToken; import com.porterhead.rest.user.domain.Role; -import com.porterhead.rest.user.domain.SessionToken; import com.porterhead.rest.user.domain.User; import com.porterhead.rest.user.exception.AuthenticationException; import com.porterhead.rest.user.exception.AuthorizationException; @@ -98,24 +98,24 @@ public void validLoginWithEmailAddress() throws Exception { AuthenticatedUserToken loginUserToken = userService.login(loginRequest); assertThat(loginUserToken.getUserId(), is(createdUserToken.getUserId())); User user = userRepository.findByUuid(loginUserToken.getUserId()); - //check that a new token was issued - assertThat(user.getSessions().first().getToken(), is(not(createdUserToken.getToken()))); - assertThat(user.getSessions().first().getToken(), is(loginUserToken.getToken())); + assertThat(user.getAuthorizationToken().getToken(), is(createdUserToken.getToken())); + //check that the same token is returned + assertThat(user.getAuthorizationToken().getToken(), is(loginUserToken.getToken())); assertThat(user.isVerified(), is(false)); } @Test - public void multipleLoginsGetDifferentSessionToken() { + public void multipleLoginsGetSameAuthToken() { CreateUserRequest request = getDefaultCreateUserRequest(); AuthenticatedUserToken createdUserToken = userService.createUser(request, Role.authenticated); LoginRequest loginRequest = new LoginRequest(); loginRequest.setUsername(request.getUser().getEmailAddress()); loginRequest.setPassword(request.getPassword().getPassword()); - String session1 = userService.login(loginRequest).getToken(); - String session2 = userService.login(loginRequest).getToken(); + String token1 = userService.login(loginRequest).getToken(); + String token2 = userService.login(loginRequest).getToken(); - assertThat(session1, is(not(session2))); + assertThat(token1, is(token2)); } @Test(expected = ValidationException.class) @@ -212,52 +212,4 @@ public void updateUserWithInvalidEmailAddress() { userService.saveUser(token.getUserId().toString(), request); } - @Test - public void getMostRecentSession() { - CreateUserRequest request = getDefaultCreateUserRequest(); - AuthenticatedUserToken token = userService.createUser(request, Role.authenticated); - String sessionToken = token.getToken(); - LoginRequest loginRequest = new LoginRequest(); - loginRequest.setUsername(request.getUser().getEmailAddress()); - loginRequest.setPassword(request.getPassword().getPassword()); - String session1 = userService.login(loginRequest).getToken(); - String session2 = userService.login(loginRequest).getToken(); - User user = userRepository.findByUuid(token.getUserId()); - assertThat(user.getSessions().size(), is(3)); - assertThat(user.getSessions().first().getToken(), is(session2)); //most recently updated session - - } - - @Test - public void saveActiveSession() { - CreateUserRequest request = getDefaultCreateUserRequest(); - AuthenticatedUserToken token = userService.createUser(request, Role.authenticated); - LoginRequest loginRequest = new LoginRequest(); - loginRequest.setUsername(request.getUser().getEmailAddress()); - loginRequest.setPassword(request.getPassword().getPassword()); - AuthenticatedUserToken loginToken = userService.login(loginRequest); - User user = userRepository.findByUuid(token.getUserId()); - SessionToken oldestToken = user.getSessions().last(); - oldestToken.setLastUpdated(new Date()); - userRepository.save(user); - user = userRepository.findByUuid(token.getUserId()); - //most recently used token is now the login token - assertThat(user.getSessions().first().getToken(), is(oldestToken.getToken())); - } - - @Test - public void cleanUpExpiredSessions() { - - CreateUserRequest request = getDefaultCreateUserRequest(); - AuthenticatedUserToken token = userService.createUser(request, Role.authenticated); - LoginRequest loginRequest = new LoginRequest(); - loginRequest.setUsername(request.getUser().getEmailAddress()); - loginRequest.setPassword(request.getPassword().getPassword()); - userService.login(loginRequest); - userService.login(loginRequest); - userService.deleteExpiredSessions(-1); - User user = userRepository.findByUuid(token.getUserId()); - assertThat(user.getSessions().size(), is(0)); - } - } diff --git a/src/test/java/com/porterhead/rest/user/resource/UserResourceTest.java b/src/test/java/com/porterhead/rest/user/resource/UserResourceTest.java index 3bac455..c2c0b06 100644 --- a/src/test/java/com/porterhead/rest/user/resource/UserResourceTest.java +++ b/src/test/java/com/porterhead/rest/user/resource/UserResourceTest.java @@ -47,7 +47,7 @@ public UserResourceTest() { @Test public void signUp() { when(userService.createUser(any(CreateUserRequest.class), any(Role.class))).thenReturn( - new AuthenticatedUserToken(TEST_USER.getUuid().toString(), ACTIVE_SESSION.getToken())); + new AuthenticatedUserToken(TEST_USER.getUuid().toString(), AUTH_TOKEN.getToken())); WebResource webResource = resource(); CreateUserRequest request = createSignupRequest(); ClientResponse response = webResource.path("user").entity(request, APPLICATION_JSON).accept(APPLICATION_JSON).post(ClientResponse.class); @@ -76,7 +76,7 @@ public void duplicateUserOnCreateUser() { @Test public void login() { when(userService.login(any(LoginRequest.class))).thenReturn( - new AuthenticatedUserToken(TEST_USER.getUuid().toString(), ACTIVE_SESSION.getToken())); + new AuthenticatedUserToken(TEST_USER.getUuid().toString(), AUTH_TOKEN.getToken())); ClientResponse response = super.resource().path("user/login").entity(createLoginRequest(), APPLICATION_JSON).accept(APPLICATION_JSON).post(ClientResponse.class); assertThat(response.getStatus(), is(200)); AuthenticatedUserToken token = response.getEntity(AuthenticatedUserToken.class); @@ -91,7 +91,7 @@ public void socialLogin() { when(connectionFactoryLocator.getConnectionFactory(any(String.class))).thenReturn(connectionFactory); when(connectionFactory.createConnection(any(AccessGrant.class))).thenReturn(connection); when(userService.socialLogin(connection)).thenReturn( - new AuthenticatedUserToken(TEST_USER.getUuid().toString(), ACTIVE_SESSION.getToken())); + new AuthenticatedUserToken(TEST_USER.getUuid().toString(), AUTH_TOKEN.getToken())); OAuth2Request request = new OAuth2Request(); request.setAccessToken("123"); ClientResponse response = super.resource().path("user/login/facebook").entity(request, APPLICATION_JSON).accept(APPLICATION_JSON).post(ClientResponse.class); @@ -117,7 +117,7 @@ public void authenticationErrorOnLogin() { @Test public void getUser() { - when(userService.getUser(any(ExternalUser.class), any(String.class))).thenReturn(new ExternalUser(TEST_USER, ACTIVE_SESSION)); + when(userService.getUser(any(ExternalUser.class), any(String.class))).thenReturn(new ExternalUser(TEST_USER, AUTH_TOKEN)); ClientResponse response = super.resource().path("user/" + TEST_USER.getUuid().toString()).accept(APPLICATION_JSON).get(ClientResponse.class); assertThat(response.getStatus(), is(200)); ExternalUser userResponse = response.getEntity(ExternalUser.class); @@ -135,7 +135,7 @@ public void deleteUser() { @Test public void updateUserWithNewEmailAddress() { - when(userService.saveUser(any(String.class), any(UpdateUserRequest.class))).thenReturn(new ExternalUser(TEST_USER, ACTIVE_SESSION)); + when(userService.saveUser(any(String.class), any(UpdateUserRequest.class))).thenReturn(new ExternalUser(TEST_USER, AUTH_TOKEN)); ClientResponse response = super.resource().path("user/" + TEST_USER.getUuid().toString()).entity(createUpdateUserRequest("foobar@example.com"), APPLICATION_JSON).accept(APPLICATION_JSON).put(ClientResponse.class); assertThat(response.getStatus(), is(200)); diff --git a/src/test/java/com/porterhead/rest/user/social/JpaUsersConnectionRepositoryTest.java b/src/test/java/com/porterhead/rest/user/social/JpaUsersConnectionRepositoryTest.java index 55ffbdb..1de10ef 100644 --- a/src/test/java/com/porterhead/rest/user/social/JpaUsersConnectionRepositoryTest.java +++ b/src/test/java/com/porterhead/rest/user/social/JpaUsersConnectionRepositoryTest.java @@ -1,5 +1,6 @@ package com.porterhead.rest.user.social; +import com.porterhead.rest.config.ApplicationConfig; import com.porterhead.rest.user.UserService; import com.porterhead.rest.user.UserServiceImpl; import com.porterhead.rest.user.api.AuthenticatedUserToken; @@ -12,6 +13,7 @@ import com.porterhead.rest.user.domain.User; import org.apache.commons.lang.RandomStringUtils; import org.junit.Test; +import org.mockito.Mock; import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; import org.springframework.social.connect.UserProfile; @@ -37,6 +39,7 @@ public class JpaUsersConnectionRepositoryTest extends AbstractSocialTst { private JpaUsersConnectionRepository usersConnectionRepository; private Validator validator; + private ApplicationConfig applicationConfig; public void setUpRepository() { @@ -50,11 +53,13 @@ public User answer(InvocationOnMock invocation) throws Throwable { } }); validator = Validation.buildDefaultValidatorFactory().getValidator(); + applicationConfig = mock(ApplicationConfig.class); + when(applicationConfig.getAuthorizationExpiryTimeInSeconds()).thenReturn(60 * 60); } @Test public void firstTimeConnected() { - UserService userService = new UserServiceImpl(usersConnectionRepository, validator); + UserService userService = new UserServiceImpl(usersConnectionRepository, validator, applicationConfig); ((UserServiceImpl)userService).setUserRepository(userRepository); List userIds = usersConnectionRepository.findUserIdsWithConnection(connection); assertThat(userIds.size(), is(1)); @@ -76,7 +81,7 @@ public void alreadyRegistered() { @Test public void validSocialLogin() { - UserService userService = new UserServiceImpl(usersConnectionRepository, validator); + UserService userService = new UserServiceImpl(usersConnectionRepository, validator, applicationConfig); ((UserServiceImpl)userService).setUserRepository(userRepository); UserProfileBuilder builder = new UserProfileBuilder(); UserProfile profile = builder.setFirstName("Tom").setLastName("Tucker").setEmail("tt@example.com").setUsername("ttucker").build(); @@ -93,7 +98,7 @@ public void validSocialLogin() { @Test public void updateFromSocialLogin() { - UserService userService = new UserServiceImpl(usersConnectionRepository, validator); + UserService userService = new UserServiceImpl(usersConnectionRepository, validator, applicationConfig); ((UserServiceImpl)userService).setUserRepository(userRepository); UserProfileBuilder builder = new UserProfileBuilder(); UserProfile profile = builder.setFirstName("Tom").setLastName("Tucker").setEmail("tt@example.com").setUsername("ttucker").build(); @@ -119,7 +124,7 @@ public void updateFromSocialLogin() { @Test public void loginWithEmailAddressThenSocialLogin() { //set up services - UserService userService = new UserServiceImpl(usersConnectionRepository, validator); + UserService userService = new UserServiceImpl(usersConnectionRepository, validator, applicationConfig); ((UserServiceImpl) userService).setUserRepository(userRepository); //create email account CreateUserRequest request = getCreateUserRequest(RandomStringUtils.randomAlphabetic(8) + "@example.com");