3

Hi I'm trying to implement spring's ldap authentication using the WebSecurityConfigurerAdapter class.

So far I can authenticate through the in memory method and even my corp's ldap server, however the latter method I'm only able to authenticate if I pass a hardcoded userDN and password when I create the new context, if I don't create a new context or I don't put the userDN and password, jvm throws me:

Caused by: javax.naming.NamingException: [LDAP: error code 1 - 000004DC: LdapErr: DSID-0C0906E8, comment: In order to perform this operation a successful bind must be completed on the connection., data 0, v1db1\u0000]; Remaining name: '/'

My question is, how can I get the user password and userDN from the login form so I can put it in the context? If that is not possible how can I get the context that the password and userDn are?

This is the code that I have:

@Configuration
@EnableWebMvcSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {

        auth.ldapAuthentication().userSearchFilter("(&(objectClass=user)(sAMAccountName={0}))")
          .groupSearchFilter("(&(memberOf:1.2.840.113556.1.4.1941:=CN=DL - DC859 - MIDDLEWARE,OU=Dyn,OU=Dist,OU=Security Groups,OU=POP,DC=pop,DC=corp,DC=local))")
          .contextSource(getLdapContextSource());
    }

    private LdapContextSource getLdapContextSource() throws Exception {
        LdapContextSource cs = new LdapContextSource();
        cs.setUrl("ldap://tcp-prd.pop.corp.local:389");
        cs.setBase("DC=pop,DC=corp,DC=local");
        cs.setUserDn("t8951435@pop.corp.local");
        cs.setPassword("mypassword");
        cs.afterPropertiesSet();
        return cs;
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
            .antMatchers("/resources/**").permitAll()
            .anyRequest().authenticated()
            .and()
            .formLogin()
            .loginPage("/login")
            .permitAll();     
    }

}

Thank you.

  • There are two modes when using LDAP authentication. In first you know how to construct user's DN based on his username (it can even be the DN itself). In second, you need to perform an LDAP search to find the user's DN. For the latter you need to have a technical login so that LDAP authentication components can find the user entry. And that is what you should be using judging on your example. You should ask your LDAP administrators to create technical account for your application and use that in your `LdapContextSource`. – Pavel Horal May 29 '15 at 17:18
  • I know the userDN will always be what the user puts in the username box + @pop.corp.local. I first tought that auth knew the context and had the username inside it, but that doesn't seem to be true, thus I have to make a new context. I just don't know how to get the credentials from there. – breno silva May 29 '15 at 17:32
  • That is not DN, that is domain logon name. But maybe you can log in with that to Active Directory. I am not sure. – Pavel Horal May 29 '15 at 17:33
  • There are two fields, DN and userDN. the DN is "DC=pop,DC=corp,DC=local". – breno silva May 29 '15 at 17:36
  • Nope. DN is a specific thing as defined by [RFC 4514](https://www.ietf.org/rfc/rfc4514.txt). The base DN is context base DN, i.e. base of the LDAP tree (i.e. where your tree starts). To what you are referring as userDN should be DN as well. You are not providing DN there, but a user's [principal name](https://msdn.microsoft.com/en-us/library/windows/desktop/aa380525%28v=vs.85%29.aspx) instead. – Pavel Horal May 29 '15 at 17:41
  • i see, This is very confusing, I've implemented this before in php and I only had to set the dn "DC=pop,DC=corp,DC=local" and the filters. – breno silva May 29 '15 at 17:46
  • Looking at a coworker's code she uses DirContext ctx; ctx.search("DC=pop,DC=corp,DC=local", filter, constraints); Does any of spring adapters have a similar method to search? – breno silva May 29 '15 at 19:10
  • Where does she take the context from... it needs to be authenticated. This is what `LdapContextSource` is for. – Pavel Horal May 29 '15 at 21:17
  • Ok, but I still have the problem of how do I get the username and password from the form. – breno silva Jun 01 '15 at 19:01

1 Answers1

2

I've finally figured it out from this post. I still don't know how to set the group filters, but at least now I can bind to the server.

 @Bean
 public ActiveDirectoryLdapAuthenticationProvider activeDirectoryLdapAuthenticationProvider() {
     ActiveDirectoryLdapAuthenticationProvider provider = new ActiveDirectoryLdapAuthenticationProvider("pop.corp.local", 
             "ldap://tcp-prd.pop.corp.local:389");
        provider.setConvertSubErrorCodesToExceptions(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 {
    http
        .authorizeRequests()
            .antMatchers("/resources/**").permitAll()
            .anyRequest().authenticated()
            .and()
        .formLogin()
            .loginPage("/login")
            .permitAll();     
}

EDIT: I finally found out how to filter by groups. It turns out that they added a setSearchFilter() method in ActiveDirectoryLdapAuthenticationProvider class v3.2.6. As I am using an older version I never knew about this. So I made a copy of the class with the method and just created a buildFilter method to create the filter string that is passed to the setSearchFilter.

Community
  • 1
  • 1