diff --git a/core/src/main/resources/org/springframework/security/messages.properties b/core/src/main/resources/org/springframework/security/messages.properties index 912e71af40..d8a012087f 100644 --- a/core/src/main/resources/org/springframework/security/messages.properties +++ b/core/src/main/resources/org/springframework/security/messages.properties @@ -30,6 +30,10 @@ DigestAuthenticationFilter.usernameNotFound=Username {0} not found JdbcDaoImpl.noAuthority=User {0} has no GrantedAuthority JdbcDaoImpl.notFound=User {0} not found LdapAuthenticationProvider.badCredentials=Bad credentials +LdapAuthenticationProvider.credentialsExpired=User credentials have expired +LdapAuthenticationProvider.disabled=User is disabled +LdapAuthenticationProvider.expired=User account has expired +LdapAuthenticationProvider.locked=User account is locked LdapAuthenticationProvider.emptyUsername=Empty username not allowed LdapAuthenticationProvider.onlySupports=Only UsernamePasswordAuthenticationToken is supported PasswordComparisonAuthenticator.badCredentials=Bad credentials @@ -39,4 +43,4 @@ RememberMeAuthenticationProvider.incorrectKey=The presented RememberMeAuthentica RunAsImplAuthenticationProvider.incorrectKey=The presented RunAsUserToken does not contain the expected key SubjectDnX509PrincipalExtractor.noMatching=No matching pattern was found in subjectDN: {0} SwitchUserFilter.noCurrentUser=No current user associated with this request -SwitchUserFilter.noOriginalAuthentication=Could not find original Authentication object \ No newline at end of file +SwitchUserFilter.noOriginalAuthentication=Could not find original Authentication object diff --git a/ldap/src/main/java/org/springframework/security/ldap/authentication/ad/ActiveDirectoryLdapAuthenticationProvider.java b/ldap/src/main/java/org/springframework/security/ldap/authentication/ad/ActiveDirectoryLdapAuthenticationProvider.java index 39ac0f1b48..a3d795844b 100644 --- a/ldap/src/main/java/org/springframework/security/ldap/authentication/ad/ActiveDirectoryLdapAuthenticationProvider.java +++ b/ldap/src/main/java/org/springframework/security/ldap/authentication/ad/ActiveDirectoryLdapAuthenticationProvider.java @@ -2,42 +2,84 @@ package org.springframework.security.ldap.authentication.ad; import org.springframework.ldap.core.DirContextOperations; import org.springframework.ldap.core.DistinguishedName; +import org.springframework.ldap.support.LdapUtils; +import org.springframework.security.authentication.AccountExpiredException; import org.springframework.security.authentication.BadCredentialsException; +import org.springframework.security.authentication.CredentialsExpiredException; +import org.springframework.security.authentication.DisabledException; +import org.springframework.security.authentication.LockedException; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.AuthorityUtils; import org.springframework.security.core.authority.SimpleGrantedAuthority; -import org.springframework.security.ldap.LdapUtils; import org.springframework.security.ldap.SpringSecurityLdapTemplate; import org.springframework.security.ldap.authentication.AbstractLdapAuthenticationProvider; import org.springframework.util.Assert; import org.springframework.util.StringUtils; +import javax.naming.AuthenticationException; import javax.naming.Context; import javax.naming.NamingException; +import javax.naming.OperationNotSupportedException; import javax.naming.directory.SearchControls; import javax.naming.ldap.InitialLdapContext; import javax.naming.ldap.LdapContext; import java.util.*; +import java.util.regex.Matcher; +import java.util.regex.Pattern; /** * Specialized LDAP authentication provider which uses Active Directory configuration conventions. *
- * It will authenticate using the Active Directory {@code userPrincipalName} (in the form {@code username@domain}). - * If the {@code usernameIncludesDomain} property is set to {@code true}, it is assumed that the user types in the - * full value, including the domain. Otherwise (the default), the {@code userPrincipalName} will be built from the - * username supplied in the authentication request. + * It will authenticate using the Active Directory + * {@code userPrincipalName} + * (in the form {@code username@domain}). If the username does not already end with the domain name, the + * {@code userPrincipalName} will be built by appending the configured domain name to the username supplied in the + * authentication request. If no domain name is configured, it is assumed that the username will always contain the + * domain name. *
* The user authorities are obtained from the data contained in the {@code memberOf} attribute. * + *
+ * If this property is set to {@code true}, the exception message from a failed bind attempt will be parsed + * for the AD-specific error code and a {@link CredentialsExpiredException}, {@link DisabledException}, + * {@link AccountExpiredException} or {@link LockedException} will be thrown for the corresponding codes. All + * other codes will result in the default {@code BadCredentialsException}. + * + * @param convertSubErrorCodesToExceptions {@code true} to raise an exception based on the AD error code. + */ + public void setConvertSubErrorCodesToExceptions(boolean convertSubErrorCodesToExceptions) { + this.convertSubErrorCodesToExceptions = convertSubErrorCodesToExceptions; } + } diff --git a/ldap/src/test/java/org/springframework/security/ldap/authentication/ad/ActiveDirectoryLdapAuthenticationProviderTests.java b/ldap/src/test/java/org/springframework/security/ldap/authentication/ad/ActiveDirectoryLdapAuthenticationProviderTests.java index d95e3b1683..dd61e14d62 100644 --- a/ldap/src/test/java/org/springframework/security/ldap/authentication/ad/ActiveDirectoryLdapAuthenticationProviderTests.java +++ b/ldap/src/test/java/org/springframework/security/ldap/authentication/ad/ActiveDirectoryLdapAuthenticationProviderTests.java @@ -1,25 +1,45 @@ package org.springframework.security.ldap.authentication.ad; import static org.junit.Assert.*; +import static org.mockito.Mockito.mock; import org.junit.*; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.Authentication; import org.springframework.security.core.authority.SimpleGrantedAuthority; +import javax.naming.Context; +import javax.naming.InitialContext; +import javax.naming.NamingException; +import javax.naming.ldap.LdapContext; +import javax.naming.spi.InitialContextFactory; +import javax.naming.spi.InitialContextFactoryBuilder; +import javax.naming.spi.NamingManager; +import java.util.*; + /** * @author Luke Taylor */ public class ActiveDirectoryLdapAuthenticationProviderTests { @Test - public void simpleAuthenticationWithIsSucessful() throws Exception { + public void bindPrincipalIsCreatedCorrectly() throws Exception { ActiveDirectoryLdapAuthenticationProvider provider = - new ActiveDirectoryLdapAuthenticationProvider(null, "ldap://192.168.1.200/"); - - Authentication result = provider.authenticate(new UsernamePasswordAuthenticationToken("luke@fenetres.monkeymachine.eu","p!ssw0rd")); - - assertEquals(1, result.getAuthorities().size()); - assertTrue(result.getAuthorities().contains(new SimpleGrantedAuthority("blah"))); + new ActiveDirectoryLdapAuthenticationProvider("mydomain.eu", "ldap://192.168.1.200/"); + assertEquals("joe@mydomain.eu", provider.createBindPrincipal("joe")); + assertEquals("joe@mydomain.eu", provider.createBindPrincipal("joe@mydomain.eu")); } + +// @Test +// public void realAuthenticationIsSucessful() throws Exception { +// ActiveDirectoryLdapAuthenticationProvider provider = +// new ActiveDirectoryLdapAuthenticationProvider(null, "ldap://192.168.1.200/"); +// +// provider.setConvertSubErrorCodesToExceptions(true); +// +// Authentication result = provider.authenticate(new UsernamePasswordAuthenticationToken("luke@fenetres.monkeymachine.eu","p!ssw0rd")); +// +// assertEquals(1, result.getAuthorities().size()); +// assertTrue(result.getAuthorities().contains(new SimpleGrantedAuthority("blah"))); +// } }