浏览代码

Improved comments and made TokenBasedRememberMeServices modular to support subclasses

Vishal Puri 18 年之前
父节点
当前提交
ef38844a6d

+ 6 - 2
core/src/main/java/org/acegisecurity/ui/AbstractProcessingFilter.java

@@ -127,7 +127,8 @@ import javax.servlet.http.HttpServletResponse;
  * </p>
  * 
  * @author Ben Alex
- * @version $Id$
+ * @version $Id: AbstractProcessingFilter.java 1909 2007-06-19 04:08:19Z
+ * vishalpuri $
  */
 public abstract class AbstractProcessingFilter implements Filter, InitializingBean, ApplicationEventPublisherAware,
 		MessageSourceAware, ApplicationContextAware {
@@ -224,12 +225,15 @@ public abstract class AbstractProcessingFilter implements Filter, InitializingBe
 		Assert.notNull(this.rememberMeServices);
 	}
 
+	/**
+	 * Use the first autodetected instance of <code>RememberMeServices</code>
+	 */
 	private void autoDetectRememberMeServices() {
 		if (applicationContext != null) {
 			Map map = applicationContext.getBeansOfType(RememberMeServices.class);
 			if (map.size() > 0) {
 				setRememberMeServices((RememberMeServices) map.values().iterator().next());
-			}      
+			}
 		}
 	}
 

+ 92 - 42
core/src/main/java/org/acegisecurity/ui/rememberme/TokenBasedRememberMeServices.java

@@ -105,12 +105,11 @@ import org.springframework.web.bind.RequestUtils;
  * @version $Id: TokenBasedRememberMeServices.java 1871 2007-05-25 03:12:49Z
  * benalex $
  */
-public class TokenBasedRememberMeServices implements RememberMeServices, InitializingBean, LogoutHandler, Ordered, ApplicationContextAware {
+public class TokenBasedRememberMeServices implements RememberMeServices, InitializingBean, LogoutHandler, Ordered,
+		ApplicationContextAware {
 	// ~ Static fields/initializers
 	// =====================================================================================
 
-	
-
 	public static final String ACEGI_SECURITY_HASHED_REMEMBER_ME_COOKIE_KEY = "ACEGI_SECURITY_HASHED_REMEMBER_ME_COOKIE";
 
 	public static final String DEFAULT_PARAMETER = "_acegi_security_remember_me";
@@ -149,13 +148,14 @@ public class TokenBasedRememberMeServices implements RememberMeServices, Initial
 		Assert.hasLength(key);
 		Assert.hasLength(parameter);
 		Assert.hasLength(cookieName);
-		Assert.notNull(applicationContext, "ApplicationContext required");
-		if (!isSetUserDetailsServiceInvoked) {
-			autoDetectAnyUserDetailsServiceAndUseIt(applicationContext);
+		if (applicationContext != null) {
+			if (!isSetUserDetailsServiceInvoked) {
+				autoDetectAndUseAnyUserDetailsService(applicationContext);
+			}
 		}
 		Assert.notNull(userDetailsService);
 	}
-	
+
 	/**
 	 * Introspects the <code>Applicationcontext</code> for the single instance
 	 * of {@link AccessDeniedHandler}. If found invoke
@@ -166,7 +166,7 @@ public class TokenBasedRememberMeServices implements RememberMeServices, Initial
 	 * 
 	 * @param applicationContext to locate the instance
 	 */
-	private void autoDetectAnyUserDetailsServiceAndUseIt(ApplicationContext applicationContext) {
+	private void autoDetectAndUseAnyUserDetailsService(ApplicationContext applicationContext) {
 		Map map = applicationContext.getBeansOfType(UserDetailsService.class);
 		if (map.size() > 1) {
 			throw new IllegalArgumentException(
@@ -177,7 +177,6 @@ public class TokenBasedRememberMeServices implements RememberMeServices, Initial
 			setUserDetailsService((UserDetailsService) map.values().iterator().next());
 		}
 	}
-		
 
 	public Authentication autoLogin(HttpServletRequest request, HttpServletResponse response) {
 		Cookie[] cookies = request.getCookies();
@@ -208,6 +207,7 @@ public class TokenBasedRememberMeServices implements RememberMeServices, Initial
 					String[] cookieTokens = StringUtils.delimitedListToStringArray(cookieAsPlainText, ":");
 
 					if (cookieTokens.length == 3) {
+
 						long tokenExpiryTime;
 
 						try {
@@ -221,8 +221,7 @@ public class TokenBasedRememberMeServices implements RememberMeServices, Initial
 							return null;
 						}
 
-						// Check it has not expired
-						if (tokenExpiryTime < System.currentTimeMillis()) {
+						if (isTokenExpired(tokenExpiryTime)) {
 							cancelCookie(request, response, "Cookie token[1] has expired (expired on '"
 									+ new Date(tokenExpiryTime) + "'; current time is '" + new Date() + "')");
 
@@ -232,25 +231,15 @@ public class TokenBasedRememberMeServices implements RememberMeServices, Initial
 						// Check the user exists
 						// Defer lookup until after expiry time checked, to
 						// possibly avoid expensive lookup
-						UserDetails userDetails;
+						UserDetails userDetails = loadUserDetails(request, response, cookieTokens);
 
-						try {
-							userDetails = this.userDetailsService.loadUserByUsername(cookieTokens[0]);
-						}
-						catch (UsernameNotFoundException notFound) {
+						if (userDetails == null) {
 							cancelCookie(request, response, "Cookie token[0] contained username '" + cookieTokens[0]
 									+ "' but was not found");
-
 							return null;
 						}
 
-						// Immediately reject if the user is not allowed to
-						// login
-						if (!userDetails.isAccountNonExpired() || !userDetails.isCredentialsNonExpired()
-								|| !userDetails.isEnabled()) {
-							cancelCookie(request, response, "Cookie token[0] contained username '" + cookieTokens[0]
-									+ "' but account has expired, credentials have expired, or user is disabled");
-
+						if (!isValidUserDetails(request, response, userDetails, cookieTokens)) {
 							return null;
 						}
 
@@ -264,8 +253,7 @@ public class TokenBasedRememberMeServices implements RememberMeServices, Initial
 						// (as if the token is valid, it will cause
 						// SecurityContextHolder population, whilst
 						// if invalid, will cause the cookie to be cancelled)
-						String expectedTokenSignature = DigestUtils.md5Hex(userDetails.getUsername() + ":"
-								+ tokenExpiryTime + ":" + userDetails.getPassword() + ":" + this.key);
+						String expectedTokenSignature = makeTokenSignature(tokenExpiryTime, userDetails);
 
 						if (!expectedTokenSignature.equals(cookieTokens[2])) {
 							cancelCookie(request, response, "Cookie token[2] contained signature '" + cookieTokens[2]
@@ -304,7 +292,55 @@ public class TokenBasedRememberMeServices implements RememberMeServices, Initial
 		return null;
 	}
 
-	private void cancelCookie(HttpServletRequest request, HttpServletResponse response, String reasonForLog) {
+	/**
+	 * @param tokenExpiryTime
+	 * @param userDetails
+	 * @return
+	 */
+	protected String makeTokenSignature(long tokenExpiryTime, UserDetails userDetails) {
+		String expectedTokenSignature = DigestUtils.md5Hex(userDetails.getUsername() + ":" + tokenExpiryTime + ":"
+				+ userDetails.getPassword() + ":" + this.key);
+		return expectedTokenSignature;
+	}
+
+	protected boolean isValidUserDetails(HttpServletRequest request, HttpServletResponse response,
+			UserDetails userDetails, String[] cookieTokens) {
+		// Immediately reject if the user is not allowed to
+		// login
+		if (!userDetails.isAccountNonExpired() || !userDetails.isCredentialsNonExpired() || !userDetails.isEnabled()) {
+			cancelCookie(request, response, "Cookie token[0] contained username '" + cookieTokens[0]
+					+ "' but account has expired, credentials have expired, or user is disabled");
+
+			return false;
+		}
+		return true;
+	}
+
+	protected UserDetails loadUserDetails(HttpServletRequest request, HttpServletResponse response,
+			String[] cookieTokens) {
+		UserDetails userDetails = null;
+
+		try {
+			userDetails = this.userDetailsService.loadUserByUsername(cookieTokens[0]);
+		}
+		catch (UsernameNotFoundException notFound) {
+			cancelCookie(request, response, "Cookie token[0] contained username '" + cookieTokens[0]
+					+ "' but was not found");
+
+			return null;
+		}
+		return userDetails;
+	}
+
+	protected boolean isTokenExpired(long tokenExpiryTime) {
+		// Check it has not expired
+		if (tokenExpiryTime < System.currentTimeMillis()) {
+			return true;
+		}
+		return false;
+	}
+
+	protected void cancelCookie(HttpServletRequest request, HttpServletResponse response, String reasonForLog) {
 		if ((reasonForLog != null) && logger.isDebugEnabled()) {
 			logger.debug("Cancelling cookie for reason: " + reasonForLog);
 		}
@@ -356,17 +392,8 @@ public class TokenBasedRememberMeServices implements RememberMeServices, Initial
 		Assert.notNull(successfulAuthentication.getPrincipal());
 		Assert.notNull(successfulAuthentication.getCredentials());
 
-		String username;
-		String password;
-
-		if (successfulAuthentication.getPrincipal() instanceof UserDetails) {
-			username = ((UserDetails) successfulAuthentication.getPrincipal()).getUsername();
-			password = ((UserDetails) successfulAuthentication.getPrincipal()).getPassword();
-		}
-		else {
-			username = successfulAuthentication.getPrincipal().toString();
-			password = successfulAuthentication.getCredentials().toString();
-		}
+		String username = retrieveUserName(successfulAuthentication);
+		String password = retrievePassword(successfulAuthentication);
 
 		// If unable to find a username and password, just abort as
 		// TokenBasedRememberMeServices unable to construct a valid token in
@@ -375,9 +402,6 @@ public class TokenBasedRememberMeServices implements RememberMeServices, Initial
 			return;
 		}
 
-		Assert.hasLength(username);
-		Assert.hasLength(password);
-
 		long expiryTime = System.currentTimeMillis() + (tokenValiditySeconds * 1000);
 
 		// construct token to put in cookie; format is:
@@ -400,6 +424,28 @@ public class TokenBasedRememberMeServices implements RememberMeServices, Initial
 				+ (authentication == null ? "Unknown" : authentication.getName()));
 	}
 
+	protected String retrieveUserName(Authentication successfulAuthentication) {
+		if (isInstanceOfUserDetails(successfulAuthentication)) {
+			return ((UserDetails) successfulAuthentication.getPrincipal()).getUsername();
+		}
+		else {
+			return successfulAuthentication.getPrincipal().toString();
+		}
+	}
+
+	protected String retrievePassword(Authentication successfulAuthentication) {
+		if (isInstanceOfUserDetails(successfulAuthentication)) {
+			return ((UserDetails) successfulAuthentication.getPrincipal()).getPassword();
+		}
+		else {
+			return successfulAuthentication.getCredentials().toString();
+		}
+	}
+
+	private boolean isInstanceOfUserDetails(Authentication authentication) {
+		return authentication.getPrincipal() instanceof UserDetails;
+	}
+
 	protected Cookie makeCancelCookie(HttpServletRequest request) {
 		Cookie cookie = new Cookie(cookieName, null);
 		cookie.setMaxAge(0);
@@ -459,7 +505,11 @@ public class TokenBasedRememberMeServices implements RememberMeServices, Initial
 	}
 
 	public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
-		this.applicationContext=applicationContext;
+		this.applicationContext = applicationContext;
+	}
+
+	public String getCookieName() {
+		return cookieName;
 	}
 
 }