Describe the bug In my project we have 2 SecurityFilterChains

  1. externalFilterChain for external API requests
  2. defaultlFilterChain for Angular/React client applications

We use LDAP and JDBC authentication. Both activeDirectoryLdapAuthenticationProvider and daoAuthenticationProvider injected as beans. But externalFilterChain picks up daoAuthenticationProvider even though I specifically said it to use activeDirectoryLdapAuthenticationProvider

To Reproduce

External API FilterChain:

@Bean
public SecurityFilterChain externalFilterChain(HttpSecurity http) throws Exception {
    return http.antMatcher("/api/v1/external/search/**")
        .httpBasic(basic -> {})
        .authorizeRequests(authorize -> authorize.anyRequest().authenticated())
        .authenticationProvider(activeDirectoryLdapAuthenticationProvider)
        .build();
}

Default FilterChain:

@Bean
public SecurityFilterChain defaultFilterChain(HttpSecurity http) throws Exception {
    return http
        .httpBasic(basic -> {})
        .authorizeRequests(authorize -> authorize.anyRequest().authenticated())
        .authenticationProvider(activeDirectoryLdapAuthenticationProvider())
        .authenticationProvider(daoAuthenticationProvider())
        .build();
}

AuthenticationProvider Beans:

    @Bean
    public CustomDaoAuthenticationProvider getDaoAuthenticationProvider() {
        CustomDaoAuthenticationProvider daoAuthenticationProvider = new CustomDaoAuthenticationProvider();
        daoAuthenticationProvider.setUserDetailsService(presDbUserDetailsService);
        daoAuthenticationProvider.setPasswordEncoder(passwordEncoder());
        return daoAuthenticationProvider;
    }


   @Bean
    public ActiveDirectoryLdapAuthenticationProvider activeDirectoryLdapAuthenticationProvider() {
        ActiveDirectoryLdapAuthenticationProvider activeDirectoryLdapAuthenticationProvider =
                new ActiveDirectoryLdapAuthenticationProvider(ldapProperties.getDomain(), ldapProperties.getUrl());
        activeDirectoryLdapAuthenticationProvider.setConvertSubErrorCodesToExceptions(true);
        activeDirectoryLdapAuthenticationProvider.setUserDetailsContextMapper(new UserDetailsContextMapper() {
   ..........     
})

        return activeDirectoryLdapAuthenticationProvider;
    }

Expected behavior User should be authenticated with provided Authentication Provider

Reports that include a sample will take priority over reports that do not. At times, we may require a sample, so it is good to try and include a sample up front.

Comment From: pavankjadda

Could be related #10005

Comment From: jzheaux

@pavankjadda, when I copy the beans into my IDE, they don't compile due to referring to several other components in your application.

Will you please post a minimal sample? The best way is to share a GitHub repo that has only the necessary components to reproduce the issue.

Comment From: pavankjadda

I created new repository that reproduces the issue. Make sure replace the AD config based on your environment.

Comment From: jzheaux

Sorry for the delay on this ticket, @pavankjadda.

I believe this is because HttpSecurity will pick up all authentication providers from beans as well as the DSL and consolidate them.

What I'd recommend instead is to formulate two AuthenticationManagers and set them on your DSLs like so:

@Bean
public SecurityFilterChain externalFilterChain(HttpSecurity http, 
        ActiveDirectoryLdapAuthenticationProvider activeDirectoryLdapAuthenticationProvider) throws Exception {

        ProviderManager manager = new ProviderManager(activeDirectoryLdapAuthenticationProvider);

    return http.antMatcher("/api/v1/external/search/**")
        .httpBasic(basic -> {})
        .authorizeRequests(authorize -> authorize.anyRequest().authenticated())
        .authenticationManager(manager)
        .build();
}

@Bean
public SecurityFilterChain defaultFilterChain(HttpSecurity http,
        ActiveDirectoryLdapAuthenticationProvider activeDirectoryLdapAuthenticationProvider,
        DaoAuthenticationProvider daoAuthenticationProvider) throws Exception {

        ProviderManager manager = new ProviderManager(
                activeDirectoryLdapAuthenticationProvider, daoAuthenticationProvider);

    return http
        .httpBasic(basic -> {})
        .authorizeRequests(authorize -> authorize.anyRequest().authenticated())
        .authenticationManager(manager)
        .build();
}

Because there is only one component for the DSL to decide on in this case, the precedence rules are a bit easier to manage with this arrangement.