فهرست منبع

SEC-3051: Add AbstractPreAuthenticatedProcessingFilter#principalChanged

Rob Winch 10 سال پیش
والد
کامیت
12ed990aa2

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

@@ -107,6 +107,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.
      */
@@ -153,17 +187,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

@@ -254,6 +254,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();