web-dev-qa-db-fra.com

Utilisation de plusieurs WebSecurityConfigurerAdapter avec différents AuthenticationProviders (authentification de base pour l'API et LDAP pour l'application Web)

Selon Spring Security Reference section 5.7 , il devrait être possible de définir plusieurs adaptateurs de sécurité.

J'essaie de faire de même mais sans succès. Après un redémarrage du serveur, les x premières fois que l'API fonctionne correctement avec l'authentification de base, mais après quelques fois, je suis redirigé vers la page de connexion (formulaire), cela ne devrait se produire que pour notre application Web, pas pour les appels d'API.

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

Une idée?

J'utilise Spring Boot version 1.4.1-RELEASE et Spring Security version 4.1.3-RELEASE.

14
Dimi

Vous utilisez le même AuthenticationManager pour les deux configurations, car vous autowire le même AuthenticationManagerBuilder .

Voir Spring Security Architecture :

@Configuration
public class ApplicationSecurity extends WebSecurityConfigurerAdapter {

    ... // web stuff here

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

}

Cet exemple concerne une application Web, mais l'utilisation de AuthenticationManagerBuilder est plus largement applicable (voir ci-dessous pour plus de détails sur la façon dont la sécurité des applications Web est implémentée). Notez que AuthenticationManagerBuilder est @Autowired dans une méthode dans un @Bean - c'est ce qui fait qu'il construit le gestionnaire d'authentification global (parent). En revanche, si nous l'avions fait de cette façon:

@Configuration
public class ApplicationSecurity extends WebSecurityConfigurerAdapter {

    @Autowired
    DataSource dataSource;

    ... // web stuff here

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

}

(en utilisant un @Override d'une méthode dans le configurateur) alors le AuthenticationManagerBuilder n'est utilisé que pour construire un "local" AuthenticationManager, qui est un enfant du global.

9
dur