Explorar o código

SEC-1190: Added "checkForPrincipalChanges" property to AbstactPreAuthenticatedProcessingFilter.

Luke Taylor %!s(int64=16) %!d(string=hai) anos
pai
achega
3cc47c9c4d

+ 33 - 1
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 <code>Authentication</code> 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 <tt>Authentication</tt> 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
      */

+ 24 - 0
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<Authentication>() {