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

This commit is contained in:
Luke Taylor 2008-11-27 21:08:01 +00:00
parent 4d81d750cd
commit 843d0e6910
3 changed files with 80 additions and 34 deletions

View File

@ -16,6 +16,7 @@
package org.springframework.security.ldap; package org.springframework.security.ldap;
import org.springframework.ldap.core.DirContextOperations; 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. * @param username the login name supplied to the authentication service.
* *
* @return a DirContextOperations object containing the user's full DN and requested attributes. * @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;
} }

View File

@ -28,6 +28,7 @@ import org.springframework.security.ldap.populator.DefaultLdapAuthoritiesPopulat
import org.springframework.security.providers.AuthenticationProvider; import org.springframework.security.providers.AuthenticationProvider;
import org.springframework.security.providers.UsernamePasswordAuthenticationToken; import org.springframework.security.providers.UsernamePasswordAuthenticationToken;
import org.springframework.security.userdetails.UserDetails; 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.LdapUserDetailsMapper;
import org.springframework.security.userdetails.ldap.UserDetailsContextMapper; import org.springframework.security.userdetails.ldap.UserDetailsContextMapper;
import org.springframework.security.util.AuthorityUtils; import org.springframework.security.util.AuthorityUtils;
@ -137,6 +138,7 @@ public class LdapAuthenticationProvider implements AuthenticationProvider {
private LdapAuthoritiesPopulator authoritiesPopulator; private LdapAuthoritiesPopulator authoritiesPopulator;
private UserDetailsContextMapper userDetailsContextMapper = new LdapUserDetailsMapper(); private UserDetailsContextMapper userDetailsContextMapper = new LdapUserDetailsMapper();
private boolean useAuthenticationRequestCredentials = true; private boolean useAuthenticationRequestCredentials = true;
private boolean hideUserNotFoundExceptions = true;
//~ Constructors =================================================================================================== //~ Constructors ===================================================================================================
@ -193,6 +195,10 @@ public class LdapAuthenticationProvider implements AuthenticationProvider {
return userDetailsContextMapper; 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 * 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 * 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); UserDetails user = userDetailsContextMapper.mapUserFromContext(userData, username, extraAuthorities);
return createSuccessfulAuthentication(userToken, user); return createSuccessfulAuthentication(userToken, user);
} catch (UsernameNotFoundException notFound) {
if (hideUserNotFoundExceptions) {
throw new BadCredentialsException(messages.getMessage(
"LdapAuthenticationProvider.badCredentials", "Bad credentials"));
} else {
throw notFound;
}
} catch (NamingException ldapAccessFailure) { } catch (NamingException ldapAccessFailure) {
throw new AuthenticationServiceException(ldapAccessFailure.getMessage(), ldapAccessFailure); throw new AuthenticationServiceException(ldapAccessFailure.getMessage(), ldapAccessFailure);
} }

View File

@ -15,24 +15,28 @@
package org.springframework.security.providers.ldap; package org.springframework.security.providers.ldap;
import org.springframework.security.Authentication; import static org.junit.Assert.*;
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.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.ArrayList;
import java.util.List; 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.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;
/** /**
* Tests {@link LdapAuthenticationProvider}. * Tests {@link LdapAuthenticationProvider}.
@ -40,19 +44,12 @@ import java.util.List;
* @author Luke Taylor * @author Luke Taylor
* @version $Id$ * @version $Id$
*/ */
public class LdapAuthenticationProviderTests extends TestCase { public class LdapAuthenticationProviderTests {
//~ Constructors =================================================================================================== Mockery jmock = new JUnit4Mockery();
public LdapAuthenticationProviderTests(String string) {
super(string);
}
public LdapAuthenticationProviderTests() {
}
//~ Methods ======================================================================================================== //~ Methods ========================================================================================================
@Test
public void testSupportsUsernamePasswordAuthenticationToken() { public void testSupportsUsernamePasswordAuthenticationToken() {
LdapAuthenticationProvider ldapProvider = new LdapAuthenticationProvider(new MockAuthenticator(), LdapAuthenticationProvider ldapProvider = new LdapAuthenticationProvider(new MockAuthenticator(),
new MockAuthoritiesPopulator()); new MockAuthoritiesPopulator());
@ -60,6 +57,7 @@ public class LdapAuthenticationProviderTests extends TestCase {
assertTrue(ldapProvider.supports(UsernamePasswordAuthenticationToken.class)); assertTrue(ldapProvider.supports(UsernamePasswordAuthenticationToken.class));
} }
@Test
public void testDefaultMapperIsSet() { public void testDefaultMapperIsSet() {
LdapAuthenticationProvider ldapProvider = new LdapAuthenticationProvider(new MockAuthenticator(), LdapAuthenticationProvider ldapProvider = new LdapAuthenticationProvider(new MockAuthenticator(),
new MockAuthoritiesPopulator()); new MockAuthoritiesPopulator());
@ -67,6 +65,7 @@ public class LdapAuthenticationProviderTests extends TestCase {
assertTrue(ldapProvider.getUserDetailsContextMapper() instanceof LdapUserDetailsMapper); assertTrue(ldapProvider.getUserDetailsContextMapper() instanceof LdapUserDetailsMapper);
} }
@Test
public void testEmptyOrNullUserNameThrowsException() { public void testEmptyOrNullUserNameThrowsException() {
LdapAuthenticationProvider ldapProvider = new LdapAuthenticationProvider(new MockAuthenticator(), LdapAuthenticationProvider ldapProvider = new LdapAuthenticationProvider(new MockAuthenticator(),
new MockAuthoritiesPopulator()); new MockAuthoritiesPopulator());
@ -82,15 +81,46 @@ public class LdapAuthenticationProviderTests extends TestCase {
} catch (BadCredentialsException expected) {} } catch (BadCredentialsException expected) {}
} }
public void testEmptyPasswordIsRejected() { @Test(expected=BadCredentialsException.class)
public void emptyPasswordIsRejected() {
LdapAuthenticationProvider ldapProvider = new LdapAuthenticationProvider(new MockAuthenticator()); LdapAuthenticationProvider ldapProvider = new LdapAuthenticationProvider(new MockAuthenticator());
try {
ldapProvider.authenticate(new UsernamePasswordAuthenticationToken("jen", "")); ldapProvider.authenticate(new UsernamePasswordAuthenticationToken("jen", ""));
fail("Expected BadCredentialsException for empty password");
} catch (BadCredentialsException expected) {}
} }
public void testNormalUsage() { @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 {
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);
}
@Test
public void normalUsage() {
MockAuthoritiesPopulator populator = new MockAuthoritiesPopulator(); MockAuthoritiesPopulator populator = new MockAuthoritiesPopulator();
LdapAuthenticationProvider ldapProvider = new LdapAuthenticationProvider(new MockAuthenticator(), populator); LdapAuthenticationProvider ldapProvider = new LdapAuthenticationProvider(new MockAuthenticator(), populator);
LdapUserDetailsMapper userMapper = new LdapUserDetailsMapper(); LdapUserDetailsMapper userMapper = new LdapUserDetailsMapper();
@ -116,7 +146,8 @@ public class LdapAuthenticationProviderTests extends TestCase {
assertTrue(authorities.contains("ROLE_FROM_POPULATOR")); assertTrue(authorities.contains("ROLE_FROM_POPULATOR"));
} }
public void testPasswordIsSetFromUserDataIfUseAuthenticationRequestCredentialsIsFalse() { @Test
public void passwordIsSetFromUserDataIfUseAuthenticationRequestCredentialsIsFalse() {
LdapAuthenticationProvider ldapProvider = new LdapAuthenticationProvider(new MockAuthenticator(), LdapAuthenticationProvider ldapProvider = new LdapAuthenticationProvider(new MockAuthenticator(),
new MockAuthoritiesPopulator()); new MockAuthoritiesPopulator());
ldapProvider.setUseAuthenticationRequestCredentials(false); 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()); LdapAuthenticationProvider ldapProvider = new LdapAuthenticationProvider(new MockAuthenticator());
LdapUserDetailsMapper userMapper = new LdapUserDetailsMapper(); LdapUserDetailsMapper userMapper = new LdapUserDetailsMapper();
userMapper.setRoleAttributes(new String[] {"ou"}); userMapper.setRoleAttributes(new String[] {"ou"});