diff --git a/web/src/main/java/org/springframework/security/web/authentication/www/DigestProcessingFilter.java b/web/src/main/java/org/springframework/security/web/authentication/www/DigestProcessingFilter.java index 01ed6a7304..879639af23 100644 --- a/web/src/main/java/org/springframework/security/web/authentication/www/DigestProcessingFilter.java +++ b/web/src/main/java/org/springframework/security/web/authentication/www/DigestProcessingFilter.java @@ -1,4 +1,4 @@ -/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited +/* Copyright 2004, 2005, 2006 2009 Acegi Technology Pty Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -90,10 +90,13 @@ public class DigestProcessingFilter extends GenericFilterBean implements Message private UserCache userCache = new NullUserCache(); private UserDetailsService userDetailsService; private boolean passwordAlreadyEncoded = false; + private boolean createAuthenticatedToken = false; //~ Methods ======================================================================================================== - @Override + + + @Override public void afterPropertiesSet() { Assert.notNull(userDetailsService, "A UserDetailsService is required"); Assert.notNull(authenticationEntryPoint, "A DigestProcessingFilterEntryPoint is required"); @@ -300,8 +303,14 @@ public class DigestProcessingFilter extends GenericFilterBean implements Message + "'"); } - UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(user, - user.getPassword()); + UsernamePasswordAuthenticationToken authRequest; + if (createAuthenticatedToken) { + authRequest = new UsernamePasswordAuthenticationToken(user, user.getPassword(), user.getAuthorities()); + } + else + { + authRequest = new UsernamePasswordAuthenticationToken(user, user.getPassword()); + } authRequest.setDetails(authenticationDetailsSource.buildDetails((HttpServletRequest) request)); @@ -358,4 +367,23 @@ public class DigestProcessingFilter extends GenericFilterBean implements Message public void setUserDetailsService(UserDetailsService userDetailsService) { this.userDetailsService = userDetailsService; } + + + /** + * If you set this property, the Authentication object, which is + * created after the successful digest authentication will be marked + * as authenticated and filled with the authorities loaded by + * the UserDetailsService. It therefore will not be re-authenticated + * by your AuthenticationProvider. This means, that only the password + * of the user is checked, but not the flags like isEnabled() or + * isAccountNonExpired(). You will save some time by enabling this flag, + * as otherwise your UserDetailsService will be called twice. A more secure + * option would be to introduce a cache around your UserDetailsService, but + * if you don't use these flags, you can also safely enable this option. + * + * @param createAuthenticatedToken default is false + */ + public void setCreateAuthenticatedToken(boolean createAuthenticatedToken) { + this.createAuthenticatedToken = createAuthenticatedToken; + } } diff --git a/web/src/test/java/org/springframework/security/web/authentication/www/DigestProcessingFilterTests.java b/web/src/test/java/org/springframework/security/web/authentication/www/DigestProcessingFilterTests.java index 136d09809b..7a00e65c3a 100644 --- a/web/src/test/java/org/springframework/security/web/authentication/www/DigestProcessingFilterTests.java +++ b/web/src/test/java/org/springframework/security/web/authentication/www/DigestProcessingFilterTests.java @@ -35,6 +35,7 @@ import org.junit.Before; import org.junit.Test; import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.mock.web.MockHttpServletResponse; +import org.springframework.security.core.authority.AuthorityUtils; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.cache.NullUserCache; @@ -294,6 +295,26 @@ public class DigestProcessingFilterTests { assertNotNull(SecurityContextHolder.getContext().getAuthentication()); assertEquals(USERNAME, ((UserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal()).getUsername()); + assertFalse(SecurityContextHolder.getContext().getAuthentication().isAuthenticated()); + } + + @Test + public void testNormalOperationWhenPasswordNotAlreadyEncodedAndWithoutReAuthentication() throws Exception { + String responseDigest = DigestAuthUtils.generateDigest(false, USERNAME, REALM, PASSWORD, "GET", + REQUEST_URI, QOP, NONCE, NC, CNONCE); + + request.addHeader("Authorization", + createAuthorizationHeader(USERNAME, REALM, NONCE, REQUEST_URI, responseDigest, QOP, NC, CNONCE)); + + filter.setCreateAuthenticatedToken(true); + executeFilterInContainerSimulator(filter, request, true); + + assertNotNull(SecurityContextHolder.getContext().getAuthentication()); + assertEquals(USERNAME, + ((UserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal()).getUsername()); + assertTrue(SecurityContextHolder.getContext().getAuthentication().isAuthenticated()); + assertEquals(AuthorityUtils.createAuthorityList("ROLE_ONE","ROLE_TWO"), + SecurityContextHolder.getContext().getAuthentication().getAuthorities()); } @Test