浏览代码

SEC-985: Added hideUsernameNotFoundException property to LdapAuthenticationProvider and set default to true.

Luke Taylor 17 年之前
父节点
当前提交
843d0e6910

+ 3 - 1
core/src/main/java/org/springframework/security/ldap/LdapUserSearch.java

@@ -16,6 +16,7 @@
 package org.springframework.security.ldap;
 
 import org.springframework.ldap.core.DirContextOperations;
+import org.springframework.security.userdetails.UsernameNotFoundException;
 
 
 /**
@@ -38,6 +39,7 @@ public interface LdapUserSearch {
      * @param username the login name supplied to the authentication service.
      *
      * @return a DirContextOperations object containing the user's full DN and requested attributes.
+     * @throws UsernameNotFoundException if no user with the supplied name could be located by the search.
      */
-    DirContextOperations searchForUser(String username);
+    DirContextOperations searchForUser(String username) throws UsernameNotFoundException;
 }

+ 13 - 1
core/src/main/java/org/springframework/security/providers/ldap/LdapAuthenticationProvider.java

@@ -28,6 +28,7 @@ import org.springframework.security.ldap.populator.DefaultLdapAuthoritiesPopulat
 import org.springframework.security.providers.AuthenticationProvider;
 import org.springframework.security.providers.UsernamePasswordAuthenticationToken;
 import org.springframework.security.userdetails.UserDetails;
+import org.springframework.security.userdetails.UsernameNotFoundException;
 import org.springframework.security.userdetails.ldap.LdapUserDetailsMapper;
 import org.springframework.security.userdetails.ldap.UserDetailsContextMapper;
 import org.springframework.security.util.AuthorityUtils;
@@ -137,6 +138,7 @@ public class LdapAuthenticationProvider implements AuthenticationProvider {
     private LdapAuthoritiesPopulator authoritiesPopulator;
     private UserDetailsContextMapper userDetailsContextMapper = new LdapUserDetailsMapper();
     private boolean useAuthenticationRequestCredentials = true;
+    private boolean hideUserNotFoundExceptions = true;
 
     //~ Constructors ===================================================================================================
 
@@ -193,6 +195,10 @@ public class LdapAuthenticationProvider implements AuthenticationProvider {
         return userDetailsContextMapper;
     }
 
+    public void setHideUserNotFoundExceptions(boolean hideUserNotFoundExceptions) {
+        this.hideUserNotFoundExceptions = hideUserNotFoundExceptions;
+    }
+
     /**
      * Determines whether the supplied password will be used as the credentials in the successful authentication
      * token. If set to false, then the password will be obtained from the UserDetails object
@@ -236,7 +242,13 @@ public class LdapAuthenticationProvider implements AuthenticationProvider {
             UserDetails user = userDetailsContextMapper.mapUserFromContext(userData, username, extraAuthorities);
 
             return createSuccessfulAuthentication(userToken, user);
-
+        } catch (UsernameNotFoundException notFound) {
+            if (hideUserNotFoundExceptions) {
+                throw new BadCredentialsException(messages.getMessage(
+                        "LdapAuthenticationProvider.badCredentials", "Bad credentials"));
+            } else {
+                throw notFound;
+            }
         } catch (NamingException ldapAccessFailure) {
             throw new AuthenticationServiceException(ldapAccessFailure.getMessage(), ldapAccessFailure);
         }

+ 58 - 26
core/src/test/java/org/springframework/security/providers/ldap/LdapAuthenticationProviderTests.java

@@ -15,23 +15,27 @@
 
 package org.springframework.security.providers.ldap;
 
+import static org.junit.Assert.*;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.jmock.Expectations;
+import org.jmock.Mockery;
+import org.jmock.integration.junit4.JUnit4Mockery;
+import org.junit.Test;
+import org.springframework.ldap.core.DirContextAdapter;
+import org.springframework.ldap.core.DirContextOperations;
+import org.springframework.ldap.core.DistinguishedName;
 import org.springframework.security.Authentication;
 import org.springframework.security.BadCredentialsException;
 import org.springframework.security.GrantedAuthority;
-import org.springframework.security.GrantedAuthorityImpl;
 import org.springframework.security.ldap.LdapAuthoritiesPopulator;
 import org.springframework.security.providers.UsernamePasswordAuthenticationToken;
 import org.springframework.security.userdetails.UserDetails;
+import org.springframework.security.userdetails.UsernameNotFoundException;
 import org.springframework.security.userdetails.ldap.LdapUserDetailsMapper;
 import org.springframework.security.util.AuthorityUtils;
-import org.springframework.ldap.core.DirContextAdapter;
-import org.springframework.ldap.core.DirContextOperations;
-import org.springframework.ldap.core.DistinguishedName;
-
-import junit.framework.TestCase;
-
-import java.util.ArrayList;
-import java.util.List;
 
 
 /**
@@ -40,19 +44,12 @@ import java.util.List;
  * @author Luke Taylor
  * @version $Id$
  */
-public class LdapAuthenticationProviderTests extends TestCase {
-    //~ Constructors ===================================================================================================
-
-    public LdapAuthenticationProviderTests(String string) {
-        super(string);
-    }
-
-    public LdapAuthenticationProviderTests() {
-    }
+public class LdapAuthenticationProviderTests {
+    Mockery jmock = new JUnit4Mockery();
 
     //~ Methods ========================================================================================================
 
-
+    @Test
     public void testSupportsUsernamePasswordAuthenticationToken() {
         LdapAuthenticationProvider ldapProvider = new LdapAuthenticationProvider(new MockAuthenticator(),
                 new MockAuthoritiesPopulator());
@@ -60,6 +57,7 @@ public class LdapAuthenticationProviderTests extends TestCase {
         assertTrue(ldapProvider.supports(UsernamePasswordAuthenticationToken.class));
     }
 
+    @Test
     public void testDefaultMapperIsSet() {
         LdapAuthenticationProvider ldapProvider = new LdapAuthenticationProvider(new MockAuthenticator(),
                 new MockAuthoritiesPopulator());
@@ -67,6 +65,7 @@ public class LdapAuthenticationProviderTests extends TestCase {
         assertTrue(ldapProvider.getUserDetailsContextMapper() instanceof LdapUserDetailsMapper);
     }
 
+    @Test
     public void testEmptyOrNullUserNameThrowsException() {
         LdapAuthenticationProvider ldapProvider = new LdapAuthenticationProvider(new MockAuthenticator(),
                 new MockAuthoritiesPopulator());
@@ -82,15 +81,46 @@ public class LdapAuthenticationProviderTests extends TestCase {
         } catch (BadCredentialsException expected) {}
     }
 
-    public void testEmptyPasswordIsRejected() {
+    @Test(expected=BadCredentialsException.class)
+    public void emptyPasswordIsRejected() {
         LdapAuthenticationProvider ldapProvider = new LdapAuthenticationProvider(new MockAuthenticator());
+        ldapProvider.authenticate(new UsernamePasswordAuthenticationToken("jen", ""));
+    }
+
+    @Test
+    public void usernameNotFoundExceptionIsHiddenByDefault() {
+        final LdapAuthenticator authenticator = jmock.mock(LdapAuthenticator.class);
+        final UsernamePasswordAuthenticationToken joe = new UsernamePasswordAuthenticationToken("joe", "password");
+        jmock.checking(new Expectations() {{
+            oneOf(authenticator).authenticate(joe); will(throwException(new UsernameNotFoundException("nobody")));
+        }});
+
+        LdapAuthenticationProvider provider = new LdapAuthenticationProvider(authenticator);
         try {
-            ldapProvider.authenticate(new UsernamePasswordAuthenticationToken("jen", ""));
-            fail("Expected BadCredentialsException for empty password");
-        } catch (BadCredentialsException expected) {}
+            provider.authenticate(joe);
+            fail();
+        } catch (BadCredentialsException expected) {
+            if (expected instanceof UsernameNotFoundException) {
+                fail("Exception should have been hidden");
+            }
+        }
+    }
+
+    @Test(expected=UsernameNotFoundException.class)
+    public void usernameNotFoundExceptionIsNotHiddenIfConfigured() {
+        final LdapAuthenticator authenticator = jmock.mock(LdapAuthenticator.class);
+        final UsernamePasswordAuthenticationToken joe = new UsernamePasswordAuthenticationToken("joe", "password");
+        jmock.checking(new Expectations() {{
+            oneOf(authenticator).authenticate(joe); will(throwException(new UsernameNotFoundException("nobody")));
+        }});
+
+        LdapAuthenticationProvider provider = new LdapAuthenticationProvider(authenticator);
+        provider.setHideUserNotFoundExceptions(false);
+        provider.authenticate(joe);
     }
 
-    public void testNormalUsage() {
+    @Test
+    public void normalUsage() {
         MockAuthoritiesPopulator populator = new MockAuthoritiesPopulator();
         LdapAuthenticationProvider ldapProvider = new LdapAuthenticationProvider(new MockAuthenticator(), populator);
         LdapUserDetailsMapper userMapper = new LdapUserDetailsMapper();
@@ -116,7 +146,8 @@ public class LdapAuthenticationProviderTests extends TestCase {
         assertTrue(authorities.contains("ROLE_FROM_POPULATOR"));
     }
 
-    public void testPasswordIsSetFromUserDataIfUseAuthenticationRequestCredentialsIsFalse() {
+    @Test
+    public void passwordIsSetFromUserDataIfUseAuthenticationRequestCredentialsIsFalse() {
         LdapAuthenticationProvider ldapProvider = new LdapAuthenticationProvider(new MockAuthenticator(),
                 new MockAuthoritiesPopulator());
         ldapProvider.setUseAuthenticationRequestCredentials(false);
@@ -127,7 +158,8 @@ public class LdapAuthenticationProviderTests extends TestCase {
 
     }
 
-    public void testUseWithNullAuthoritiesPopulatorReturnsCorrectRole() {
+    @Test
+    public void useWithNullAuthoritiesPopulatorReturnsCorrectRole() {
         LdapAuthenticationProvider ldapProvider = new LdapAuthenticationProvider(new MockAuthenticator());
         LdapUserDetailsMapper userMapper = new LdapUserDetailsMapper();
         userMapper.setRoleAttributes(new String[] {"ou"});