Browse Source

SEC-3: Add static method so digest-compatible passwords can be stored in database.

Ben Alex 20 years ago
parent
commit
218fcf5b24

+ 23 - 7
core/src/main/java/org/acegisecurity/ui/digestauth/DigestProcessingFilter.java

@@ -114,10 +114,15 @@ public class DigestProcessingFilter implements Filter, InitializingBean {
     private AuthenticationDao authenticationDao;
     private AuthenticationDao authenticationDao;
     private DigestProcessingFilterEntryPoint authenticationEntryPoint;
     private DigestProcessingFilterEntryPoint authenticationEntryPoint;
     private UserCache userCache = new NullUserCache();
     private UserCache userCache = new NullUserCache();
+    private boolean passwordAlreadyEncoded = false;
 
 
     //~ Methods ================================================================
     //~ Methods ================================================================
 
 
-    public void setAuthenticationDao(AuthenticationDao authenticationDao) {
+    public void setPasswordAlreadyEncoded(boolean passwordAlreadyEncoded) {
+		this.passwordAlreadyEncoded = passwordAlreadyEncoded;
+	}
+
+	public void setAuthenticationDao(AuthenticationDao authenticationDao) {
         this.authenticationDao = authenticationDao;
         this.authenticationDao = authenticationDao;
     }
     }
 
 
@@ -307,7 +312,7 @@ public class DigestProcessingFilter implements Filter, InitializingBean {
             String serverDigestMd5;
             String serverDigestMd5;
 
 
             // Don't catch IllegalArgumentException (already checked validity)
             // Don't catch IllegalArgumentException (already checked validity)
-            serverDigestMd5 = generateDigest(username, realm,
+            serverDigestMd5 = generateDigest(passwordAlreadyEncoded, username, realm,
                     user.getPassword(),
                     user.getPassword(),
                     ((HttpServletRequest) request).getMethod(), uri, qop,
                     ((HttpServletRequest) request).getMethod(), uri, qop,
                     nonce, nc, cnonce);
                     nonce, nc, cnonce);
@@ -331,7 +336,7 @@ public class DigestProcessingFilter implements Filter, InitializingBean {
                 userCache.putUserInCache(user);
                 userCache.putUserInCache(user);
 
 
                 // Don't catch IllegalArgumentException (already checked validity)
                 // Don't catch IllegalArgumentException (already checked validity)
-                serverDigestMd5 = generateDigest(username, realm,
+                serverDigestMd5 = generateDigest(passwordAlreadyEncoded, username, realm,
                         user.getPassword(),
                         user.getPassword(),
                         ((HttpServletRequest) request).getMethod(), uri, qop,
                         ((HttpServletRequest) request).getMethod(), uri, qop,
                         nonce, nc, cnonce);
                         nonce, nc, cnonce);
@@ -377,6 +382,12 @@ public class DigestProcessingFilter implements Filter, InitializingBean {
         chain.doFilter(request, response);
         chain.doFilter(request, response);
     }
     }
 
 
+    public static String encodePasswordInA1Format(String username, String realm, String password) {
+        String a1 = username + ":" + realm + ":" + password;
+        String a1Md5 = new String(DigestUtils.md5Hex(a1));
+    	return a1Md5;
+    }
+    
     /**
     /**
      * Computes the <code>response</code> portion of a Digest authentication
      * Computes the <code>response</code> portion of a Digest authentication
      * header. Both the server and user agent should compute the
      * header. Both the server and user agent should compute the
@@ -397,14 +408,19 @@ public class DigestProcessingFilter implements Filter, InitializingBean {
      *
      *
      * @throws IllegalArgumentException DOCUMENT ME!
      * @throws IllegalArgumentException DOCUMENT ME!
      */
      */
-    public static String generateDigest(String username, String realm,
+    public static String generateDigest(boolean passwordAlreadyEncoded, String username, String realm,
         String password, String httpMethod, String uri, String qop,
         String password, String httpMethod, String uri, String qop,
         String nonce, String nc, String cnonce) throws IllegalArgumentException {
         String nonce, String nc, String cnonce) throws IllegalArgumentException {
-        String a1 = username + ":" + realm + ":" + password;
+        String a1Md5 = null;
         String a2 = httpMethod + ":" + uri;
         String a2 = httpMethod + ":" + uri;
-        String a1Md5 = new String(DigestUtils.md5Hex(a1));
         String a2Md5 = new String(DigestUtils.md5Hex(a2));
         String a2Md5 = new String(DigestUtils.md5Hex(a2));
-
+        
+        if (passwordAlreadyEncoded) {
+        	a1Md5 = password;
+        } else {
+        	a1Md5 = encodePasswordInA1Format(username, realm, password);
+        }
+        
         String digest;
         String digest;
 
 
         if (qop == null) {
         if (qop == null) {

+ 78 - 27
core/src/test/java/org/acegisecurity/ui/digestauth/DigestProcessingFilterTests.java

@@ -20,11 +20,14 @@ import junit.framework.TestCase;
 import org.acegisecurity.DisabledException;
 import org.acegisecurity.DisabledException;
 import org.acegisecurity.MockFilterConfig;
 import org.acegisecurity.MockFilterConfig;
 import org.acegisecurity.UserDetails;
 import org.acegisecurity.UserDetails;
+
 import org.acegisecurity.context.SecurityContextHolder;
 import org.acegisecurity.context.SecurityContextHolder;
 import org.acegisecurity.context.SecurityContextImpl;
 import org.acegisecurity.context.SecurityContextImpl;
+
 import org.acegisecurity.providers.dao.AuthenticationDao;
 import org.acegisecurity.providers.dao.AuthenticationDao;
 import org.acegisecurity.providers.dao.UserCache;
 import org.acegisecurity.providers.dao.UserCache;
 import org.acegisecurity.providers.dao.UsernameNotFoundException;
 import org.acegisecurity.providers.dao.UsernameNotFoundException;
+
 import org.acegisecurity.util.StringSplitUtils;
 import org.acegisecurity.util.StringSplitUtils;
 
 
 import org.apache.commons.codec.binary.Base64;
 import org.apache.commons.codec.binary.Base64;
@@ -114,8 +117,8 @@ public class DigestProcessingFilterTests extends TestCase {
         String nc = "00000002";
         String nc = "00000002";
         String cnonce = "c822c727a648aba7";
         String cnonce = "c822c727a648aba7";
         String password = "koala";
         String password = "koala";
-        String responseDigest = DigestProcessingFilter.generateDigest(username,
-                realm, password, "GET", uri, qop, nonce, nc, cnonce);
+        String responseDigest = DigestProcessingFilter.generateDigest(false,
+                username, realm, password, "GET", uri, qop, nonce, nc, cnonce);
 
 
         // Setup our HTTP request
         // Setup our HTTP request
         MockHttpServletRequest request = new MockHttpServletRequest("GET", uri);
         MockHttpServletRequest request = new MockHttpServletRequest("GET", uri);
@@ -263,8 +266,8 @@ public class DigestProcessingFilterTests extends TestCase {
         String nc = "00000002";
         String nc = "00000002";
         String cnonce = "c822c727a648aba7";
         String cnonce = "c822c727a648aba7";
         String password = "koala";
         String password = "koala";
-        String responseDigest = DigestProcessingFilter.generateDigest(username,
-                realm, password, "GET", uri, qop, nonce, nc, cnonce);
+        String responseDigest = DigestProcessingFilter.generateDigest(false,
+                username, realm, password, "GET", uri, qop, nonce, nc, cnonce);
 
 
         // Setup our HTTP request
         // Setup our HTTP request
         MockHttpServletRequest request = new MockHttpServletRequest();
         MockHttpServletRequest request = new MockHttpServletRequest();
@@ -307,8 +310,8 @@ public class DigestProcessingFilterTests extends TestCase {
         String nc = "00000002";
         String nc = "00000002";
         String cnonce = "c822c727a648aba7";
         String cnonce = "c822c727a648aba7";
         String password = "koala";
         String password = "koala";
-        String responseDigest = DigestProcessingFilter.generateDigest(username,
-                realm, password, "GET", uri, qop, nonce, nc, cnonce);
+        String responseDigest = DigestProcessingFilter.generateDigest(false,
+                username, realm, password, "GET", uri, qop, nonce, nc, cnonce);
 
 
         // Setup our HTTP request
         // Setup our HTTP request
         MockHttpServletRequest request = new MockHttpServletRequest();
         MockHttpServletRequest request = new MockHttpServletRequest();
@@ -351,8 +354,8 @@ public class DigestProcessingFilterTests extends TestCase {
         String nc = "00000002";
         String nc = "00000002";
         String cnonce = "c822c727a648aba7";
         String cnonce = "c822c727a648aba7";
         String password = "koala";
         String password = "koala";
-        String responseDigest = DigestProcessingFilter.generateDigest(username,
-                realm, password, "GET", uri, qop, nonce, nc, cnonce);
+        String responseDigest = DigestProcessingFilter.generateDigest(false,
+                username, realm, password, "GET", uri, qop, nonce, nc, cnonce);
 
 
         // Setup our HTTP request
         // Setup our HTTP request
         MockHttpServletRequest request = new MockHttpServletRequest();
         MockHttpServletRequest request = new MockHttpServletRequest();
@@ -395,8 +398,8 @@ public class DigestProcessingFilterTests extends TestCase {
         String nc = "00000002";
         String nc = "00000002";
         String cnonce = "c822c727a648aba7";
         String cnonce = "c822c727a648aba7";
         String password = "koala";
         String password = "koala";
-        String responseDigest = DigestProcessingFilter.generateDigest(username,
-                realm, password, "GET", uri, qop, nonce, nc, cnonce);
+        String responseDigest = DigestProcessingFilter.generateDigest(false,
+                username, realm, password, "GET", uri, qop, nonce, nc, cnonce);
 
 
         // Setup our HTTP request
         // Setup our HTTP request
         MockHttpServletRequest request = new MockHttpServletRequest();
         MockHttpServletRequest request = new MockHttpServletRequest();
@@ -426,7 +429,54 @@ public class DigestProcessingFilterTests extends TestCase {
         assertEquals(401, response.getStatus());
         assertEquals(401, response.getStatus());
     }
     }
 
 
-    public void testNormalOperation() throws Exception {
+    public void testNormalOperationWhenPasswordIsAlreadyEncoded()
+        throws Exception {
+        Map responseHeaderMap = generateValidHeaders(60);
+
+        String username = "marissa";
+        String realm = (String) responseHeaderMap.get("realm");
+        String nonce = (String) responseHeaderMap.get("nonce");
+        String uri = "/some_file.html";
+        String qop = (String) responseHeaderMap.get("qop");
+        String nc = "00000002";
+        String cnonce = "c822c727a648aba7";
+        String password = DigestProcessingFilter.encodePasswordInA1Format(username,
+                realm, "koala");
+        String responseDigest = DigestProcessingFilter.generateDigest(true,
+                username, realm, password, "GET", uri, qop, nonce, nc, cnonce);
+
+        // Setup our HTTP request
+        MockHttpServletRequest request = new MockHttpServletRequest("GET", uri);
+        request.addHeader("Authorization",
+            createAuthorizationHeader(username, realm, nonce, uri,
+                responseDigest, qop, nc, cnonce));
+        request.setServletPath("/some_file.html");
+
+        // Launch an application context and access our bean
+        ApplicationContext ctx = new ClassPathXmlApplicationContext(
+                "org/acegisecurity/ui/digestauth/filtertest-valid.xml");
+        DigestProcessingFilter filter = (DigestProcessingFilter) ctx.getBean(
+                "digestProcessingFilter");
+
+        // Setup our filter configuration
+        MockFilterConfig config = new MockFilterConfig();
+
+        // Setup our expectation that the filter chain will be invoked
+        MockFilterChain chain = new MockFilterChain(true);
+        MockHttpServletResponse response = new MockHttpServletResponse();
+
+        // Test
+        executeFilterInContainerSimulator(config, filter, request, response,
+            chain);
+
+        assertNotNull(SecurityContextHolder.getContext().getAuthentication());
+        assertEquals("marissa",
+            ((UserDetails) SecurityContextHolder.getContext().getAuthentication()
+                                                .getPrincipal()).getUsername());
+    }
+
+    public void testNormalOperationWhenPasswordNotAlreadyEncoded()
+        throws Exception {
         Map responseHeaderMap = generateValidHeaders(60);
         Map responseHeaderMap = generateValidHeaders(60);
 
 
         String username = "marissa";
         String username = "marissa";
@@ -437,8 +487,8 @@ public class DigestProcessingFilterTests extends TestCase {
         String nc = "00000002";
         String nc = "00000002";
         String cnonce = "c822c727a648aba7";
         String cnonce = "c822c727a648aba7";
         String password = "koala";
         String password = "koala";
-        String responseDigest = DigestProcessingFilter.generateDigest(username,
-                realm, password, "GET", uri, qop, nonce, nc, cnonce);
+        String responseDigest = DigestProcessingFilter.generateDigest(false,
+                username, realm, password, "GET", uri, qop, nonce, nc, cnonce);
 
 
         // Setup our HTTP request
         // Setup our HTTP request
         MockHttpServletRequest request = new MockHttpServletRequest("GET", uri);
         MockHttpServletRequest request = new MockHttpServletRequest("GET", uri);
@@ -466,8 +516,8 @@ public class DigestProcessingFilterTests extends TestCase {
 
 
         assertNotNull(SecurityContextHolder.getContext().getAuthentication());
         assertNotNull(SecurityContextHolder.getContext().getAuthentication());
         assertEquals("marissa",
         assertEquals("marissa",
-            ((UserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal())
-            .getUsername());
+            ((UserDetails) SecurityContextHolder.getContext().getAuthentication()
+                                                .getPrincipal()).getUsername());
     }
     }
 
 
     public void testOtherAuthorizationSchemeIsIgnored()
     public void testOtherAuthorizationSchemeIsIgnored()
@@ -535,8 +585,8 @@ public class DigestProcessingFilterTests extends TestCase {
         String nc = "00000002";
         String nc = "00000002";
         String cnonce = "c822c727a648aba7";
         String cnonce = "c822c727a648aba7";
         String password = "koala";
         String password = "koala";
-        String responseDigest = DigestProcessingFilter.generateDigest(username,
-                realm, password, "GET", uri, qop, nonce, nc, cnonce);
+        String responseDigest = DigestProcessingFilter.generateDigest(false,
+                username, realm, password, "GET", uri, qop, nonce, nc, cnonce);
 
 
         // Setup our HTTP request
         // Setup our HTTP request
         MockHttpServletRequest request = new MockHttpServletRequest("GET", uri);
         MockHttpServletRequest request = new MockHttpServletRequest("GET", uri);
@@ -566,8 +616,8 @@ public class DigestProcessingFilterTests extends TestCase {
 
 
         // Now retry, giving an invalid nonce
         // Now retry, giving an invalid nonce
         password = "WRONG_PASSWORD";
         password = "WRONG_PASSWORD";
-        responseDigest = DigestProcessingFilter.generateDigest(username, realm,
-                password, "GET", uri, qop, nonce, nc, cnonce);
+        responseDigest = DigestProcessingFilter.generateDigest(false, username,
+                realm, password, "GET", uri, qop, nonce, nc, cnonce);
 
 
         request = new MockHttpServletRequest();
         request = new MockHttpServletRequest();
         request.addHeader("Authorization",
         request.addHeader("Authorization",
@@ -593,8 +643,9 @@ public class DigestProcessingFilterTests extends TestCase {
         String nc = "00000002";
         String nc = "00000002";
         String cnonce = "NOT_SAME_AS_USED_FOR_DIGEST_COMPUTATION";
         String cnonce = "NOT_SAME_AS_USED_FOR_DIGEST_COMPUTATION";
         String password = "koala";
         String password = "koala";
-        String responseDigest = DigestProcessingFilter.generateDigest(username,
-                realm, password, "GET", uri, qop, nonce, nc, "DIFFERENT_CNONCE");
+        String responseDigest = DigestProcessingFilter.generateDigest(false,
+                username, realm, password, "GET", uri, qop, nonce, nc,
+                "DIFFERENT_CNONCE");
 
 
         // Setup our HTTP request
         // Setup our HTTP request
         MockHttpServletRequest request = new MockHttpServletRequest("GET", uri);
         MockHttpServletRequest request = new MockHttpServletRequest("GET", uri);
@@ -635,8 +686,8 @@ public class DigestProcessingFilterTests extends TestCase {
         String nc = "00000002";
         String nc = "00000002";
         String cnonce = "c822c727a648aba7";
         String cnonce = "c822c727a648aba7";
         String password = "WRONG_PASSWORD";
         String password = "WRONG_PASSWORD";
-        String responseDigest = DigestProcessingFilter.generateDigest(username,
-                realm, password, "GET", uri, qop, nonce, nc, cnonce);
+        String responseDigest = DigestProcessingFilter.generateDigest(false,
+                username, realm, password, "GET", uri, qop, nonce, nc, cnonce);
 
 
         // Setup our HTTP request
         // Setup our HTTP request
         MockHttpServletRequest request = new MockHttpServletRequest("GET", uri);
         MockHttpServletRequest request = new MockHttpServletRequest("GET", uri);
@@ -677,8 +728,8 @@ public class DigestProcessingFilterTests extends TestCase {
         String nc = "00000002";
         String nc = "00000002";
         String cnonce = "c822c727a648aba7";
         String cnonce = "c822c727a648aba7";
         String password = "koala";
         String password = "koala";
-        String responseDigest = DigestProcessingFilter.generateDigest(username,
-                realm, password, "GET", uri, qop, nonce, nc, cnonce);
+        String responseDigest = DigestProcessingFilter.generateDigest(false,
+                username, realm, password, "GET", uri, qop, nonce, nc, cnonce);
 
 
         // Setup our HTTP request
         // Setup our HTTP request
         MockHttpServletRequest request = new MockHttpServletRequest("GET", uri);
         MockHttpServletRequest request = new MockHttpServletRequest("GET", uri);
@@ -719,8 +770,8 @@ public class DigestProcessingFilterTests extends TestCase {
         String nc = "00000002";
         String nc = "00000002";
         String cnonce = "c822c727a648aba7";
         String cnonce = "c822c727a648aba7";
         String password = "koala";
         String password = "koala";
-        String responseDigest = DigestProcessingFilter.generateDigest(username,
-                realm, password, "GET", uri, qop, nonce, nc, cnonce);
+        String responseDigest = DigestProcessingFilter.generateDigest(false,
+                username, realm, password, "GET", uri, qop, nonce, nc, cnonce);
 
 
         // Setup our HTTP request
         // Setup our HTTP request
         MockHttpServletRequest request = new MockHttpServletRequest("GET", uri);
         MockHttpServletRequest request = new MockHttpServletRequest("GET", uri);