diff --git a/web/src/main/java/org/springframework/security/web/authentication/preauth/AbstractPreAuthenticatedProcessingFilter.java b/web/src/main/java/org/springframework/security/web/authentication/preauth/AbstractPreAuthenticatedProcessingFilter.java index 14127c135a..988321f325 100755 --- a/web/src/main/java/org/springframework/security/web/authentication/preauth/AbstractPreAuthenticatedProcessingFilter.java +++ b/web/src/main/java/org/springframework/security/web/authentication/preauth/AbstractPreAuthenticatedProcessingFilter.java @@ -49,6 +49,8 @@ public abstract class AbstractPreAuthenticatedProcessingFilter extends GenericFi private boolean continueFilterChainOnUnsuccessfulAuthentication = true; + private boolean checkForPrincipalChanges; + /** * Check whether all required properties have been set. */ @@ -67,9 +69,10 @@ public abstract class AbstractPreAuthenticatedProcessingFilter extends GenericFi logger.debug("Checking secure context token: " + SecurityContextHolder.getContext().getAuthentication()); } - if (SecurityContextHolder.getContext().getAuthentication() == null) { + if (requiresAuthentication((HttpServletRequest) request)) { doAuthenticate((HttpServletRequest) request, (HttpServletResponse) response); } + chain.doFilter(request, response); } @@ -108,6 +111,24 @@ public abstract class AbstractPreAuthenticatedProcessingFilter extends GenericFi } } + private boolean requiresAuthentication(HttpServletRequest request) { + Authentication currentUser = SecurityContextHolder.getContext().getAuthentication(); + + if (currentUser == null) { + return true; + } + + Object principal = getPreAuthenticatedPrincipal(request); + if (checkForPrincipalChanges && + !currentUser.getName().equals(principal)) { + logger.debug("Pre-authenticated principal has changed to " + principal + " and will be reauthenticated"); + + return true; + } + + return false; + } + /** * Puts the Authentication instance returned by the * authentication manager into the secure context. @@ -165,6 +186,17 @@ public abstract class AbstractPreAuthenticatedProcessingFilter extends GenericFi continueFilterChainOnUnsuccessfulAuthentication = shouldContinue; } + /** + * If set, the pre-authenticated principal will be checked on each request and compared + * against the name of the current Authentication object. If a change is detected, + * the user will be reauthenticated. + * + * @param checkForPrincipalChanges + */ + public void setCheckForPrincipalChanges(boolean checkForPrincipalChanges) { + this.checkForPrincipalChanges = checkForPrincipalChanges; + } + /** * Override to extract the principal information from the current request */ diff --git a/web/src/test/java/org/springframework/security/web/authentication/preauth/header/RequestHeaderPreAuthenticatedProcessingFilterTests.java b/web/src/test/java/org/springframework/security/web/authentication/preauth/header/RequestHeaderPreAuthenticatedProcessingFilterTests.java index c860fd9012..72322c2c7c 100644 --- a/web/src/test/java/org/springframework/security/web/authentication/preauth/header/RequestHeaderPreAuthenticatedProcessingFilterTests.java +++ b/web/src/test/java/org/springframework/security/web/authentication/preauth/header/RequestHeaderPreAuthenticatedProcessingFilterTests.java @@ -87,6 +87,30 @@ public class RequestHeaderPreAuthenticatedProcessingFilterTests { assertEquals("catspassword", SecurityContextHolder.getContext().getAuthentication().getCredentials()); } + @Test + public void userIsReauthenticatedIfPrincipalChangesAndCheckForPrincipalChangesIsSet() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest(); + MockHttpServletResponse response = new MockHttpServletResponse(); + RequestHeaderPreAuthenticatedProcessingFilter filter = new RequestHeaderPreAuthenticatedProcessingFilter(); + filter.setAuthenticationManager(createAuthenticationManager()); + filter.setCheckForPrincipalChanges(true); + request.addHeader("SM_USER", "cat"); + filter.doFilter(request, response, new MockFilterChain()); + request = new MockHttpServletRequest(); + request.addHeader("SM_USER", "dog"); + filter.doFilter(request, response, new MockFilterChain()); + Authentication dog = SecurityContextHolder.getContext().getAuthentication(); + assertNotNull(dog); + assertEquals("dog", dog.getName()); + // Make sure authentication doesn't occur every time (i.e. if the header *doesn't change) + filter.setAuthenticationManager(mock(AuthenticationManager.class)); + filter.doFilter(request, response, new MockFilterChain()); + assertSame(dog, SecurityContextHolder.getContext().getAuthentication()); + } + + /** + * Create an authentication manager which returns the passed in object. + */ private AuthenticationManager createAuthenticationManager() { AuthenticationManager am = mock(AuthenticationManager.class); when(am.authenticate(any(Authentication.class))).thenAnswer(new Answer() {