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

18,501

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.

Share:
18,501
Dimi
Author by

Dimi

Updated on June 03, 2022

Comments

  • Dimi
    Dimi almost 2 years

    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.