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() {