diff --git a/core/src/main/java/org/acegisecurity/ui/digestauth/DigestProcessingFilter.java b/core/src/main/java/org/acegisecurity/ui/digestauth/DigestProcessingFilter.java index fb78ee414e..013dcd2cfc 100644 --- a/core/src/main/java/org/acegisecurity/ui/digestauth/DigestProcessingFilter.java +++ b/core/src/main/java/org/acegisecurity/ui/digestauth/DigestProcessingFilter.java @@ -114,10 +114,15 @@ public class DigestProcessingFilter implements Filter, InitializingBean { private AuthenticationDao authenticationDao; private DigestProcessingFilterEntryPoint authenticationEntryPoint; private UserCache userCache = new NullUserCache(); + private boolean passwordAlreadyEncoded = false; //~ Methods ================================================================ - public void setAuthenticationDao(AuthenticationDao authenticationDao) { + public void setPasswordAlreadyEncoded(boolean passwordAlreadyEncoded) { + this.passwordAlreadyEncoded = passwordAlreadyEncoded; + } + + public void setAuthenticationDao(AuthenticationDao authenticationDao) { this.authenticationDao = authenticationDao; } @@ -307,7 +312,7 @@ public class DigestProcessingFilter implements Filter, InitializingBean { String serverDigestMd5; // Don't catch IllegalArgumentException (already checked validity) - serverDigestMd5 = generateDigest(username, realm, + serverDigestMd5 = generateDigest(passwordAlreadyEncoded, username, realm, user.getPassword(), ((HttpServletRequest) request).getMethod(), uri, qop, nonce, nc, cnonce); @@ -331,7 +336,7 @@ public class DigestProcessingFilter implements Filter, InitializingBean { userCache.putUserInCache(user); // Don't catch IllegalArgumentException (already checked validity) - serverDigestMd5 = generateDigest(username, realm, + serverDigestMd5 = generateDigest(passwordAlreadyEncoded, username, realm, user.getPassword(), ((HttpServletRequest) request).getMethod(), uri, qop, nonce, nc, cnonce); @@ -377,6 +382,12 @@ public class DigestProcessingFilter implements Filter, InitializingBean { 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 response portion of a Digest authentication * header. Both the server and user agent should compute the @@ -397,14 +408,19 @@ public class DigestProcessingFilter implements Filter, InitializingBean { * * @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 nonce, String nc, String cnonce) throws IllegalArgumentException { - String a1 = username + ":" + realm + ":" + password; + String a1Md5 = null; String a2 = httpMethod + ":" + uri; - String a1Md5 = new String(DigestUtils.md5Hex(a1)); String a2Md5 = new String(DigestUtils.md5Hex(a2)); - + + if (passwordAlreadyEncoded) { + a1Md5 = password; + } else { + a1Md5 = encodePasswordInA1Format(username, realm, password); + } + String digest; if (qop == null) { diff --git a/core/src/test/java/org/acegisecurity/ui/digestauth/DigestProcessingFilterTests.java b/core/src/test/java/org/acegisecurity/ui/digestauth/DigestProcessingFilterTests.java index b2ad230f69..98938e027e 100644 --- a/core/src/test/java/org/acegisecurity/ui/digestauth/DigestProcessingFilterTests.java +++ b/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.MockFilterConfig; import org.acegisecurity.UserDetails; + import org.acegisecurity.context.SecurityContextHolder; import org.acegisecurity.context.SecurityContextImpl; + import org.acegisecurity.providers.dao.AuthenticationDao; import org.acegisecurity.providers.dao.UserCache; import org.acegisecurity.providers.dao.UsernameNotFoundException; + import org.acegisecurity.util.StringSplitUtils; import org.apache.commons.codec.binary.Base64; @@ -114,8 +117,8 @@ public class DigestProcessingFilterTests extends TestCase { String nc = "00000002"; String cnonce = "c822c727a648aba7"; 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 MockHttpServletRequest request = new MockHttpServletRequest("GET", uri); @@ -263,8 +266,8 @@ public class DigestProcessingFilterTests extends TestCase { String nc = "00000002"; String cnonce = "c822c727a648aba7"; 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 MockHttpServletRequest request = new MockHttpServletRequest(); @@ -307,8 +310,8 @@ public class DigestProcessingFilterTests extends TestCase { String nc = "00000002"; String cnonce = "c822c727a648aba7"; 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 MockHttpServletRequest request = new MockHttpServletRequest(); @@ -351,8 +354,8 @@ public class DigestProcessingFilterTests extends TestCase { String nc = "00000002"; String cnonce = "c822c727a648aba7"; 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 MockHttpServletRequest request = new MockHttpServletRequest(); @@ -395,8 +398,8 @@ public class DigestProcessingFilterTests extends TestCase { String nc = "00000002"; String cnonce = "c822c727a648aba7"; 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 MockHttpServletRequest request = new MockHttpServletRequest(); @@ -426,7 +429,8 @@ public class DigestProcessingFilterTests extends TestCase { assertEquals(401, response.getStatus()); } - public void testNormalOperation() throws Exception { + public void testNormalOperationWhenPasswordIsAlreadyEncoded() + throws Exception { Map responseHeaderMap = generateValidHeaders(60); String username = "marissa"; @@ -436,9 +440,10 @@ public class DigestProcessingFilterTests extends TestCase { String qop = (String) responseHeaderMap.get("qop"); String nc = "00000002"; String cnonce = "c822c727a648aba7"; - String password = "koala"; - String responseDigest = DigestProcessingFilter.generateDigest(username, - realm, password, "GET", uri, qop, nonce, nc, cnonce); + 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); @@ -466,8 +471,53 @@ public class DigestProcessingFilterTests extends TestCase { assertNotNull(SecurityContextHolder.getContext().getAuthentication()); assertEquals("marissa", - ((UserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal()) - .getUsername()); + ((UserDetails) SecurityContextHolder.getContext().getAuthentication() + .getPrincipal()).getUsername()); + } + + public void testNormalOperationWhenPasswordNotAlreadyEncoded() + 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 = "koala"; + String responseDigest = DigestProcessingFilter.generateDigest(false, + 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 testOtherAuthorizationSchemeIsIgnored() @@ -535,8 +585,8 @@ public class DigestProcessingFilterTests extends TestCase { String nc = "00000002"; String cnonce = "c822c727a648aba7"; 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 MockHttpServletRequest request = new MockHttpServletRequest("GET", uri); @@ -566,8 +616,8 @@ public class DigestProcessingFilterTests extends TestCase { // Now retry, giving an invalid nonce 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.addHeader("Authorization", @@ -593,8 +643,9 @@ public class DigestProcessingFilterTests extends TestCase { String nc = "00000002"; String cnonce = "NOT_SAME_AS_USED_FOR_DIGEST_COMPUTATION"; 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 MockHttpServletRequest request = new MockHttpServletRequest("GET", uri); @@ -635,8 +686,8 @@ public class DigestProcessingFilterTests extends TestCase { String nc = "00000002"; String cnonce = "c822c727a648aba7"; 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 MockHttpServletRequest request = new MockHttpServletRequest("GET", uri); @@ -677,8 +728,8 @@ public class DigestProcessingFilterTests extends TestCase { String nc = "00000002"; String cnonce = "c822c727a648aba7"; 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 MockHttpServletRequest request = new MockHttpServletRequest("GET", uri); @@ -719,8 +770,8 @@ public class DigestProcessingFilterTests extends TestCase { String nc = "00000002"; String cnonce = "c822c727a648aba7"; 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 MockHttpServletRequest request = new MockHttpServletRequest("GET", uri);