Active Directory-Authentifizierung mit Spring Security 3.2, Spring Ldap 2.0 und JavaConfig

Ich schreibe eine Webanwendung, für die sich Benutzer anmelden müssen. Mein Unternehmen verfügt über einen Active Directory-Server, den ich zu diesem Zweck nutzen möchte. Bei der Verwendung von Spring zur Authentifizierung der Benutzeranmeldeinformationen treten jedoch Probleme auf.

Ich verwende Spring Security 3.2.2, Spring Ldap 2.0.1 und Java 1.7.

Die Webanwendung startet gut, die Authentifizierung gegen InMemory-Authentifizierung funktioniert auch gut, daher scheint der Rest meiner Anwendung korrekt konfiguriert zu sein.

Hier ist meine Konfig:

@Configuration
@,EnableWebSecurity
public class LdapConfig extends WebSecurityConfigurerAdapter {

    @Bean
    public ActiveDirectoryLdapAuthenticationProvider activeDirectoryLdapAuthenticationProvider() {
        val provider = new ActiveDirectoryLdapAuthenticationProvider("my.domain", "ldap://LDAP_ID:389/OU=A_GROUP,DC=domain,DC=tld");
        provider.setConvertSubErrorCodesToExceptions(true);
        provider.setUseAuthenticationRequestCredentials(true);
        provider.setUseAuthenticationRequestCredentials(true);
        return provider;
    }

    @Bean
    public LoggerListener loggerListener() {
        return new LoggerListener();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(activeDirectoryLdapAuthenticationProvider());
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // Configuration for Redirects, Login-Page and stuff
    }   
}

Wenn ich versuche, mich mit MY_USERNAME und MY_PASSWORD anzumelden, erhalte ich eineAuthentication request failed: org.springframework.security.authentication.BadCredentialsException: Bad credentials

Vollständiger Stacktrace:

14:59:00,508 DEBUG UsernamePasswordAuthenticationFilter:205 - Request is to process authentication
14:59:00,509 DEBUG ProviderManager:152 - Authentication attempt using org.springframework.security.ldap.authentication.ad.ActiveDirectoryLdapAuthenticationProvider
14:59:00,509 DEBUG ActiveDirectoryLdapAuthenticationProvider:65 - Processing authentication request for user: USERNAME
14:59:00,563 ERROR ActiveDirectoryLdapAuthenticationProvider:133 - Failed to locate directory entry for authenticated user: USERNAME
javax.naming.NameNotFoundException: [LDAP: error code 32 - 0000208D: NameErr: DSID-0310020A, problem 2001 (NO_OBJECT), data 0, best match of:
    'OU=A_GROUP,DC=domain,DC=tld'
    at com.sun.jndi.ldap.LdapCtx.mapErrorCode(Unknown Source)
    at com.sun.jndi.ldap.LdapCtx.processReturnCode(Unknown Source)
    at com.sun.jndi.ldap.LdapCtx.processReturnCode(Unknown Source)
    at com.sun.jndi.ldap.LdapCtx.searchAux(Unknown Source)
    at com.sun.jndi.ldap.LdapCtx.c_search(Unknown Source)
    at com.sun.jndi.ldap.LdapCtx.c_search(Unknown Source)
    at com.sun.jndi.toolkit.ctx.ComponentDirContext.p_search(Unknown Source)
    at com.sun.jndi.toolkit.ctx.PartialCompositeDirContext.search(Unknown Source)
    at javax.naming.directory.InitialDirContext.search(Unknown Source)
    at org.springframework.security.ldap.SpringSecurityLdapTemplate.searchForSingleEntryInternal(SpringSecurityLdapTemplate.java:208)
    at org.springframework.security.ldap.authentication.ad.ActiveDirectoryLdapAuthenticationProvider.searchForUser(ActiveDirectoryLdapAuthenticationProvider.java:285)
    at org.springframework.security.ldap.authentication.ad.ActiveDirectoryLdapAuthenticationProvider.doAuthentication(ActiveDirectoryLdapAuthenticationProvider.java:130)
    at org.springframework.security.ldap.authentication.AbstractLdapAuthenticationProvider.authenticate(AbstractLdapAuthenticationProvider.java:80)
    at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:156)
    at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:177)
    at org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter.attemptAuthentication(UsernamePasswordAuthenticationFilter.java:94)
    at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:211)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
    at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:110)
    ... a few more

14:59:00,597  WARN LoggerListener:60 - Authentication event AuthenticationFailureBadCredentialsEvent: USERNAME; details: org.springframework.security.web.authentication.WebAuthenticationDetails@0: RemoteIpAddUSERNAME: 0:0:0:0:0:0:0:1; SessionId: 1E9401031886F0155F0ACE881CC50A4B; exception: Bad credentials
14:59:00,597 DEBUG UsernamePasswordAuthenticationFilter:348 - Authentication request failed: org.springframework.security.authentication.BadCredentialsException: Bad credentials
14:59:00,597 DEBUG UsernamePasswordAuthenticationFilter:349 - Updated SecurityContextHolder to contain null Authentication
14:59:00,597 DEBUG UsernamePasswordAuthenticationFilter:350 - Delegating to authentication failure handler org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler@3d876453

Wenn ich die AD mit einem Ldap-Explorer durchsuche und suche nach(&(objectClass=user)(userPrincipalName=MY_USERNAME)), die Spring in ActiveDirectoryLdapAuthenticationProvider: searchForUser (...) ausführt, gibt den richtigen Benutzer zurück.

Bei Eingabe eines ungültigen Passworts kehrt Spring zurückActiveDirectoryLdapAuthenticationProvider:200 - Active Directory authentication failed: Supplied password was invalid. Das scheint in Ordnung zu sein.

Fehlt ein Teil für die Konfiguration?

Gibt es funktionierende Beispiele für die Konfiguration von Spring Ldap für ein AD mit JavaConfig? Der offizielle Spring Guide beschreibt nur den XML-Weghttp://docs.spring.io/spring-security/site/docs/3.1.5.RELEASE/reference/ldap.html#ldap-active-directory

Aktualisieren: Soeben wurde mein AuthenticationProvider auf Folgendes aktualisiert:

@Bean
public ActiveDirectoryLdapAuthenticationProvider activeDirectoryLdapAuthenticationProvider() {
    val provider = new ActiveDirectoryLdapAuthenticationProvider("company.tld", "ldap://LDAP_URL:389");
    provider.setConvertSubErrorCodesToExceptions(true);
    provider.setUseAuthenticationRequestCredentials(true);

    provider.setAuthoritiesMapper(myAuthoritiesMapper()); // see http://comdynamics.net/blog/544/spring-security-3-integration-with-active-directory-ldap/

    provider.setUseAuthenticationRequestCredentials(true);

    return provider;
}

Es funktioniert gut, danke Guido!

Hinweis: Spring gibt an, dass eine PartialResultException ignoriert wird. Die Docs sagen

Einige Active Directory-Server (AD-Server) können Verweise nicht automatisch verfolgen, was häufig dazu führt, dass bei Suchvorgängen eine PartialResultException ausgelöst wird. Sie können angeben, dass PartialResultException ignoriert werden soll, indem Sie die Eigenschaft ignorePartialResultException auf true setzen.

Möglicherweise gibt es auch eine Möglichkeit, diese Eigenschaft über JavaConfig festzulegen. Ich habe es einfach ignoriert.

Antworten auf die Frage(1)

Ihre Antwort auf die Frage