Using multiple WebSecurityConfigurerAdapter with different AuthenticationProviders (basic auth for API and LDAP for web app)

basic-authentication, java, spring, spring-boot, spring-security

Solution

You use the same `AuthenticationManager` for both configurations, because you autowire the same `AuthenticationManagerBuilder`.

See Spring Security Architecture:

@Configuration
public class ApplicationSecurity extends WebSecurityConfigurerAdapter {

    ... // web stuff here

    @Autowired
    public void initialize(AuthenticationManagerBuilder builder, DataSource dataSource) {
        builder.jdbcAuthentication().dataSource(dataSource).withUser("dave")
            .password("secret").roles("USER");
    }

}

This example relates to a web application, but the usage of `AuthenticationManagerBuilder` is more widely applicable (see below for more detail on how web application security is implemented). Note that the `AuthenticationManagerBuilder` is `@Autowired` into a method in a `@Bean` - that is what makes it build the global (parent) AuthenticationManager. In contrast if we had done it this way:

@Configuration
public class ApplicationSecurity extends WebSecurityConfigurerAdapter {

    @Autowired
    DataSource dataSource;

    ... // web stuff here

    @Override
    public void configure(AuthenticationManagerBuilder builder) {
        builder.jdbcAuthentication().dataSource(dataSource).withUser("dave")
            .password("secret").roles("USER");
    }

}

(using an `@Override` of a method in the configurer) then the `AuthenticationManagerBuilder` is only used to build a "local" `AuthenticationManager`, which is a child of the global one.

Problem

According the Spring Security Reference section 5.7 it should be possible to define more than one security adapter. I try to do the same but without success. After a server reboot, the first x times the API works fine with basic auth, but after a couple of times I'm redirected to the login (form) page, this should only happen for our web app, not for the API calls. My code: ``` @EnableWebSecurity public class MultiHttpSecurityConfig { @Configuration @Order(1) public static class ApiWebSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter { @Autowired private Environment env; @Autowired public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { auth.inMemoryAuthentication(). withUser("admin").password("pw_test").roles(API_ROLE); } protected void configure(HttpSecurity http) throws Exception { http .antMatcher("/services/**") .authorizeRequests() .anyRequest().hasRole(API_ROLE) .and() .httpBasic() .and() .csrf() .disable(); } } @Configuration @Order(2) public static class FormLoginWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter { @Autowired private Environment env; @Autowired public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { auth.authenticationProvider(activeDirectoryLdapAuthenticationProvider()); auth.eraseCredentials(false); } @Override protected void configure(HttpSecurity http) throws Exception { // LDAP FORM AUTHENTICATION http.authorizeRequests() .antMatchers("/login.html").permitAll() .antMatchers("/css/**").permitAll() .antMatchers("/js/**").permitAll() .antMatchers("/images/**").permitAll() .anyRequest().authenticated() .and().formLogin() .failureUrl("/login.html?error=1") .loginPage("/login.html") .loginProcessingUrl("/j_spring_security_check") .defaultSuccessUrl("/success.html") .usernameParameter("j_username") .passwordParameter("j_password") .permitAll(); http.csrf().disable(); // iFRAMES SETTINGS http .headers() .frameOptions().sameOrigin() .httpStrictTransportSecurity().disable(); // HTTPS http .requiresChannel() .anyRequest() .requiresSecure(); //MAP 8080 to HTTPS PORT http.portMapper().http(8080).mapsTo(443); } @Bean public AuthenticationProvider activeDirectoryLdapAuthenticationProvider() { CustomLdapAuthenticationProvider provider = new CustomLdapAuthenticationProvider(env.getProperty("ldap.domain"), env.getProperty("ldap.url"), env.getProperty("ldap.base")); provider.setConvertSubErrorCodesToExceptions(true); provider.setUseAuthenticationRequestCredentials(true); return provider; } } } ``` Any idea? I'm using Spring Boot version 1.4.1-RELEASE and Spring Security version 4.1.3-RELEASE.

Original source