springspring-bootspring-securityspring-security-ldap

spring security 5.7 - multiple authentication provider without WebSecurityConfigurerAdapter


I'm using spring security 5.7 and WebSecurityConfigurerAdapter is deprecated. I want use multiple Authentication Provider(Ldap and Dao) but ldap provider not working and spring security just call DaoAuthenticationProvider.

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfiguration {

@Autowired
private JWTTokenFilter jwtTokenFilter;

@Autowired
private LdapAuthProvider ldapAuthProvider;

@Autowired
private UserService userService;

@Bean
public DaoAuthenticationProvider authenticationProvider() {
    DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider();
    authProvider.setUserDetailsService(userService);
    authProvider.setPasswordEncoder(passwordEncoder());
    return authProvider;
}

@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
    http
            .cors()
            .and().csrf().disable()
            .headers().frameOptions().disable()
            .and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
            .and().authorizeRequests().antMatchers("/api/test/**", "/auth/**", "/h2-console/**").permitAll()
            .and().authorizeRequests().anyRequest().authenticated()
            .and().addFilterBefore(jwtTokenFilter, UsernamePasswordAuthenticationFilter.class);
    http.authenticationProvider(ldapAuthProvider);
    http.authenticationProvider(authenticationProvider());
    return http.build();
}

@Bean
public AuthenticationManager authenticationManager(
        AuthenticationConfiguration authenticationConfiguration) throws Exception {
    return authenticationConfiguration.getAuthenticationManager();
}

@Bean
public PasswordEncoder passwordEncoder() {
    return new BCryptPasswordEncoder();
}

@Bean
public CorsFilter corsFilter() {
    UrlBasedCorsConfigurationSource source =
            new UrlBasedCorsConfigurationSource();
    CorsConfiguration config = new CorsConfiguration();
    config.setAllowCredentials(true);
    config.addAllowedOrigin("*");
    config.addAllowedHeader("*");
    config.addAllowedMethod("*");
    source.registerCorsConfiguration("/**", config);
    return new CorsFilter(source);
}

}

when remove DaoAuthenticationProvider then LdapAuthProvider is work. what's the problem?

edit: i want use exposed AuthenticationManager in whole app like this:

@Autowired
private AuthenticationManager authenticationManager;

@PostMapping("/login")
public ResponseEntity<?> login(@RequestBody AuthRequest authRequest) {


    if(authRequest.getUsername() == null || authRequest.getPassword() == null) {
        return ResponseEntity.badRequest().build();
    }


    Authentication authenticate = null;
    try {
        authenticate = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(
                authRequest.getUsername(),
                authRequest.getPassword()));
    } catch (Exception e) {

        e.printStackTrace();
        return ResponseEntity.status(401).build();
    }

but this AuthenticationManager not contain my custom AuthenticationProvider


Solution

  • Below is an example of using two authentication providers (Ldap and Dao) in Spring Security 5.7. This is in the context of a traditional web application using form login. The trick was to explicitly set the AuthenticationManager to use (i.e. ProviderManager) in the filter chain and reference both authentication providers:

    @Bean
    public ActiveDirectoryLdapAuthenticationProvider getAdAuthProvider(CustomLdapUserDetailsMapper customLdapUserDetailsMapper) {
      ActiveDirectoryLdapAuthenticationProvider authProvider = new ActiveDirectoryLdapAuthenticationProvider(domain, urls);
      authProvider.setSearchFilter("(&(objectClass=user)(sAMAccountName={1}))");
      authProvider.setUserDetailsContextMapper(customLdapUserDetailsMapper);
      return authProvider;
    }
    
    @Bean
    public DaoAuthenticationProvider getDaoAuthProvider(CustomDatabaseUserDetailsService customDatabaseUserDetailsService) {
      DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
      provider.setUserDetailsService(customDatabaseUserDetailsService);
      provider.setPasswordEncoder(new BCryptPasswordEncoder());
      return provider;
    }
    
    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http, ActiveDirectoryLdapAuthenticationProvider adAuthProvider, DaoAuthenticationProvider dbAuthProvider) throws Exception {
      http.authorizeRequests()
        .antMatchers("/").permitAll()
        ...
        .anyRequest().hasAuthority("ADMIN")
        .and().formLogin().loginPage("/login").permitAll()
        .and().logout().logoutRequestMatcher(new AntPathRequestMatcher("/logout")).permitAll()
        .and().authenticationManager(new ProviderManager(List.of(adAuthProvider, dbAuthProvider)));
    
      return http.build();
    }