PartialResultException when authenticating with Spring Security and JavaConfig

Chris L picture Chris L · Nov 7, 2014 · Viewed 12.8k times · Source

I am currently creating a new web application using Spring Boot and began the process of integrating Spring Security for authentication. After successfully following the Spring Boot-based LDAP tutorial, I wanted to point my JavaConfig-based configuration to my Active Directory instance.

My application now handles bad credentials as expected, but valid credentials now result in

javax.naming.PartialResultException: Unprocessed Continuation Reference(s); remaining name ''

This is a common problem -- there are a number of places where this issue has been encountered. The solution appears to be setting Context.REFERRAL to "follow", but I can't find any documentation indicating how to set that option using JavaConfig. Is my only option here to revert to an XML-based configuration? It seems like Spring is pushing developers toward JavaConfig, so I'd like to avoid mixing the two approaches, if possible.

The following is my security configuration:

@Configuration
@EnableWebMvcSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

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

    @Configuration
    protected static class AuthenticationConfiguration extends
            GlobalAuthenticationConfigurerAdapter {

        @Override
        public void init(AuthenticationManagerBuilder auth) throws Exception {
            auth.ldapAuthentication()
                .userSearchBase("")
                .userSearchFilter("(&(cn={0}))").contextSource()
                .managerDn("<username>")
                .managerPassword("<password>")
                .url("ldap://<url>");
        }
    }
}

Answer

Chris L picture Chris L · Nov 11, 2014

I had the feeling I'd need to use an instance of LdapContextSource to make this happen (since it conveniently has a setReferral method), but I struggled a bit with the details. A forum post on spring.io gave me enough to go on, and it looks like I now have things working.

It's not clear to me if there are any significant flaws with what I'm doing here, but it seems to work, so hopefully this will be helpful to someone else in the future:

@Configuration
@EnableWebMvcSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

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

    @Configuration
    protected static class AuthenticationConfiguration extends
            GlobalAuthenticationConfigurerAdapter {

        @Override
        public void init(AuthenticationManagerBuilder auth) throws Exception {              
            DefaultSpringSecurityContextSource contextSource = new DefaultSpringSecurityContextSource("ldap://<url>");
            contextSource.setUserDn("<username>");
            contextSource.setPassword("<password>");
            contextSource.setReferral("follow"); 
            contextSource.afterPropertiesSet();

            LdapAuthenticationProviderConfigurer<AuthenticationManagerBuilder> ldapAuthenticationProviderConfigurer = auth.ldapAuthentication();

            ldapAuthenticationProviderConfigurer
                .userSearchFilter("(&(cn={0}))")
                .userSearchBase("")
                .contextSource(contextSource);
        }
    }
}