Browse Source

SEC-3051: Add AbstractPreAuthenticatedProcessingFilter#principalChanged

Rob Winch 10 years ago
parent
commit
92ae45a04d

+ 36 - 9
web/src/main/java/org/springframework/security/web/authentication/preauth/AbstractPreAuthenticatedProcessingFilter.java

@@ -116,6 +116,40 @@ public abstract class AbstractPreAuthenticatedProcessingFilter extends GenericFi
 		chain.doFilter(request, response);
 	}
 
+	/**
+	 * Determines if the current principal has changed. The default implementation tries
+	 *
+	 * <ul>
+	 * <li>If the {@link #getPreAuthenticatedPrincipal(HttpServletRequest)} is a String, the {@link Authentication#getName()} is compared against the pre authenticated principal</li>
+	 * <li>Otherwise, the {@link #getPreAuthenticatedPrincipal(HttpServletRequest)} is compared against the {@link Authentication#getPrincipal()}
+	 * </ul>
+	 *
+	 * <p>
+	 * Subclasses can override this method to determine when a principal has changed.
+	 * </p>
+	 *
+	 * @param request
+	 * @param currentAuthentication
+	 * @return true if the principal has changed, else false
+	 */
+	protected boolean principalChanged(HttpServletRequest request, Authentication currentAuthentication) {
+
+		Object principal = getPreAuthenticatedPrincipal(request);
+
+		if ((principal instanceof String) && currentAuthentication.getName().equals(principal)) {
+			return false;
+		}
+
+		if (principal != null && principal.equals(currentAuthentication.getPrincipal())) {
+			return false;
+		}
+
+		if(logger.isDebugEnabled()) {
+			logger.debug("Pre-authenticated principal has changed to " + principal + " and will be reauthenticated");
+		}
+		return true;
+	}
+
 	/**
 	 * Do the actual authentication for a pre-authenticated user.
 	 */
@@ -166,18 +200,11 @@ public abstract class AbstractPreAuthenticatedProcessingFilter extends GenericFi
 			return false;
 		}
 
-		Object principal = getPreAuthenticatedPrincipal(request);
-
-		if ((principal instanceof String) && currentUser.getName().equals(principal)) {
-			return false;
-		}
-
-		if (principal != null && principal.equals(currentUser.getPrincipal())) {
+		if(!principalChanged(request, currentUser)) {
 			return false;
 		}
 
-		logger.debug("Pre-authenticated principal has changed to " + principal
-				+ " and will be reauthenticated");
+		logger.debug("Pre-authenticated principal has changed and will be reauthenticated");
 
 		if (invalidateSessionOnPrincipalChange) {
 			SecurityContextHolder.clearContext();

+ 54 - 0
web/src/test/java/org/springframework/security/web/authentication/preauth/AbstractPreAuthenticatedProcessingFilterTests.java

@@ -274,6 +274,60 @@ public class AbstractPreAuthenticatedProcessingFilterTests {
 		verify(am).authenticate(any(PreAuthenticatedAuthenticationToken.class));
 	}
 
+	@Test
+	public void requiresAuthenticationOverridePrincipalChangedTrue() throws Exception {
+		Object principal = new Object();
+		SecurityContextHolder.getContext().setAuthentication(
+				new TestingAuthenticationToken(principal, "something", "ROLE_USER"));
+		MockHttpServletRequest request = new MockHttpServletRequest();
+		MockHttpServletResponse response = new MockHttpServletResponse();
+		MockFilterChain chain = new MockFilterChain();
+
+		ConcretePreAuthenticatedProcessingFilter filter = new ConcretePreAuthenticatedProcessingFilter() {
+			@Override
+			protected boolean principalChanged(HttpServletRequest request,
+					Authentication currentAuthentication) {
+				return true;
+			}
+		};
+		filter.setCheckForPrincipalChanges(true);
+		filter.principal = principal;
+		AuthenticationManager am = mock(AuthenticationManager.class);
+		filter.setAuthenticationManager(am);
+		filter.afterPropertiesSet();
+
+		filter.doFilter(request, response, chain);
+
+		verify(am).authenticate(any(PreAuthenticatedAuthenticationToken.class));
+	}
+
+	@Test
+	public void requiresAuthenticationOverridePrincipalChangedFalse() throws Exception {
+		Object principal = new Object();
+		SecurityContextHolder.getContext().setAuthentication(
+				new TestingAuthenticationToken(principal, "something", "ROLE_USER"));
+		MockHttpServletRequest request = new MockHttpServletRequest();
+		MockHttpServletResponse response = new MockHttpServletResponse();
+		MockFilterChain chain = new MockFilterChain();
+
+		ConcretePreAuthenticatedProcessingFilter filter = new ConcretePreAuthenticatedProcessingFilter() {
+			@Override
+			protected boolean principalChanged(HttpServletRequest request,
+					Authentication currentAuthentication) {
+				return false;
+			}
+		};
+		filter.setCheckForPrincipalChanges(true);
+		filter.principal = principal;
+		AuthenticationManager am = mock(AuthenticationManager.class);
+		filter.setAuthenticationManager(am);
+		filter.afterPropertiesSet();
+
+		filter.doFilter(request, response, chain);
+
+		verifyZeroInteractions(am);
+	}
+
 	private void testDoFilter(boolean grantAccess) throws Exception {
 		MockHttpServletRequest req = new MockHttpServletRequest();
 		MockHttpServletResponse res = new MockHttpServletResponse();