Active Directory Authentication using Spring Security 3.2, Spring Ldap 2.0 and JavaConfig
Asked Answered
D

1

18

I'm writing a web application that requires users to login. My company has an Active Directory server that I'd like to make use of for this purpose. However, I'm having trouble using Spring to authenticate the users credentials.

I'm using Spring Security 3.2.2, Spring Ldap 2.0.1 and Java 1.7.

The Web Application starts well, authentication against InMemory-Authentication works well, too, so the rest of my application seems to be configured correctly.

Here is my Config:

@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
    }   
}

When I try to login using MY_USERNAME and MY_PASSWORD I get a Authentication request failed: org.springframework.security.authentication.BadCredentialsException: Bad credentials

Full 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

When I browse the AD using a Ldap-Explorer and search for (&(objectClass=user)(userPrincipalName=MY_USERNAME)), which Spring does in ActiveDirectoryLdapAuthenticationProvider:searchForUser(...), it returns the correct user.

When entering an invalid Password, Spring returns ActiveDirectoryLdapAuthenticationProvider:200 - Active Directory authentication failed: Supplied password was invalid. This seems to be OK.

Is a part for the configuration missing?

Are there any working examples of how to configure Spring Ldap for an AD using JavaConfig? The official Spring Guide just describes the XML-Way http://docs.spring.io/spring-security/site/docs/3.1.5.RELEASE/reference/ldap.html#ldap-active-directory

Update: Just updated my AuthenticationProvider to the following:

@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;
}

It works fine, thanks guido!

Note: Spring states, that a PartialResultException is ignored. The Docs say

Some Active Directory (AD) servers are unable to automatically following referrals, which often leads to a PartialResultException being thrown in searches. You can specify that PartialResultException is to be ignored by setting the ignorePartialResultException property to true.

Maybe there is a way to set this property vie JavaConfig, too. I just ignored it.

Deangelo answered 25/4, 2014 at 14:13 Comment(7)
can you try removing the OU=A_GROUP,DC=domain,DC=tld base from your connection url? it seems the AD spring provider manage that internallyPlumbiferous
Just tried to remove this part and it kinda works. Console logs a Ignoring PartialResultException and HTTP 403 Error.Deangelo
The login-name is the value of sAMAccountName. May this be a problem as well?Deangelo
Standing at the docs, it seems you can login with the username of the full userPrincipalName ([email protected]). Pls update your question with your new findings.Plumbiferous
the link comdynamics.net/blog/544/… is outdated... care to add few more points about this myAuthoritiesMapper()?Emir
I am facing the same problem. User 'username' not found in directory. Incorrect result size: expected 1, actual 0 . but with same user and invalid password. I get proper error message. I have set a userDetailsContextMapper but not authoritiesMapper. and the link comdynamics is out dated. can you please provide more info on how you solved the issue.Dinger
Using the proper authoritiesMapper solved this for me. I just used this code, because access rights did just depend on one AD group. adProvider.setAuthoritiesMapper(new GrantedAuthoritiesMapper() { @Override public Collection<? extends GrantedAuthority> mapAuthorities(final Collection<? extends GrantedAuthority> authorities) { for (GrantedAuthority authority : authorities) { if ("management".equals(authority.getAuthority())) { return Collections.singletonList(new SimpleGrantedAuthority(Role.ADMIN)); } } return null; } });Roily
S
2
  1. For PartialResultException You should set parameter referral to "follow" on Your context source.

Eg: https://mcmap.net/q/742537/-partialresultexception-when-authenticating-with-spring-security-and-javaconfig

Sculpsit answered 20/1, 2015 at 14:47 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.