Przeglądaj źródła

SEC-1250: RequestHeaderPreAuthenticatedProcessingFilter cannot be use to fail back to another authentication type. Added exceptionIfHeaderMissing property.

Luke Taylor 16 lat temu
rodzic
commit
0da99171da

+ 21 - 5
web/src/main/java/org/springframework/security/web/authentication/preauth/RequestHeaderAuthenticationFilter.java

@@ -11,12 +11,15 @@ import org.springframework.util.Assert;
  * As with most pre-authenticated scenarios, it is essential that the external authentication system is set up
  * correctly as this filter does no authentication whatsoever. All the protection is assumed to be provided externally
  * and if this filter is included inappropriately in a configuration, it would be possible  to assume the
- * identity of a user merely by setting the correct header name. This also means it should not be used in combination
- * with other Spring Security authentication mechanisms such as form login, as this would imply there was a means of
- * bypassing the external system which would be risky.
+ * identity of a user merely by setting the correct header name. This also means it should not generally be used
+ * in combination with other Spring Security authentication mechanisms such as form login, as this would imply there
+ * was a means of bypassing the external system which would be risky.
  * <p>
  * The property <tt>principalRequestHeader</tt> is the name of the request header that contains the username. It
  * defaults to "SM_USER" for compatibility with Siteminder.
+ * <p>
+ * If the header is missing from the request, <tt>getPreAuthenticatedPrincipal</tt> will throw an exception. You
+ * can override this behaviour by setting the <tt>exceptionIfMissingHeader</tt> property.
  *
  *
  * @author Luke Taylor
@@ -26,16 +29,19 @@ import org.springframework.util.Assert;
 public class RequestHeaderAuthenticationFilter extends AbstractPreAuthenticatedProcessingFilter {
     private String principalRequestHeader = "SM_USER";
     private String credentialsRequestHeader;
+    private boolean exceptionIfHeaderMissing = true;
+    private boolean exceptionIfMissingHeader;
 
     /**
      * Read and returns the header named by <tt>principalRequestHeader</tt> from the request.
      *
-     * @throws PreAuthenticatedCredentialsNotFoundException if the header is missing
+     * @throws PreAuthenticatedCredentialsNotFoundException if the header is missing and <tt>exceptionIfHeaderMissing</tt>
+     *          is set to <tt>true</tt>.
      */
     protected Object getPreAuthenticatedPrincipal(HttpServletRequest request) {
         String principal = request.getHeader(principalRequestHeader);
 
-        if (principal == null) {
+        if (principal == null && exceptionIfHeaderMissing) {
             throw new PreAuthenticatedCredentialsNotFoundException(principalRequestHeader
                     + " header not found in request.");
         }
@@ -66,4 +72,14 @@ public class RequestHeaderAuthenticationFilter extends AbstractPreAuthenticatedP
         Assert.hasText(credentialsRequestHeader, "credentialsRequestHeader must not be empty or null");
         this.credentialsRequestHeader = credentialsRequestHeader;
     }
+
+    /**
+     * Defines whether an exception should be raised if the principal header is missing. Defaults to <tt>true</tt>.
+     *
+     * @param exceptionIfHeaderMissing set to <tt>false</tt> to override the default behaviour and allow
+     *          the request to proceed if no header is found.
+     */
+    public void setExceptionIfHeaderMissing(boolean exceptionIfHeaderMissing) {
+        this.exceptionIfHeaderMissing = exceptionIfMissingHeader;
+    }
 }

+ 23 - 1
web/src/test/java/org/springframework/security/web/authentication/preauth/header/RequestHeaderPreAuthenticatedProcessingFilterTests.java → web/src/test/java/org/springframework/security/web/authentication/preauth/header/RequestHeaderAuthenticationFilterTests.java

@@ -23,7 +23,7 @@ import org.springframework.security.web.authentication.preauth.RequestHeaderAuth
  * @author Luke Taylor
  * @version $Id$
  */
-public class RequestHeaderPreAuthenticatedProcessingFilterTests {
+public class RequestHeaderAuthenticationFilterTests {
 
     @After
     @Before
@@ -108,6 +108,28 @@ public class RequestHeaderPreAuthenticatedProcessingFilterTests {
         assertSame(dog, SecurityContextHolder.getContext().getAuthentication());
     }
 
+    @Test(expected=PreAuthenticatedCredentialsNotFoundException.class)
+    public void missingHeaderCausesException() throws Exception {
+        MockHttpServletRequest request = new MockHttpServletRequest();
+        MockHttpServletResponse response = new MockHttpServletResponse();
+        MockFilterChain chain = new MockFilterChain();
+        RequestHeaderAuthenticationFilter filter = new RequestHeaderAuthenticationFilter();
+        filter.setAuthenticationManager(createAuthenticationManager());
+
+        filter.doFilter(request, response, chain);
+    }
+
+    @Test
+    public void missingHeaderIsIgnoredIfExceptionIfHeaderMissingIsFalse() throws Exception {
+        MockHttpServletRequest request = new MockHttpServletRequest();
+        MockHttpServletResponse response = new MockHttpServletResponse();
+        MockFilterChain chain = new MockFilterChain();
+        RequestHeaderAuthenticationFilter filter = new RequestHeaderAuthenticationFilter();
+        filter.setExceptionIfHeaderMissing(false);
+        filter.setAuthenticationManager(createAuthenticationManager());
+        filter.doFilter(request, response, chain);
+    }
+
     /**
      * Create an authentication manager which returns the passed in object.
      */