How to add an additional AuthenticationProvider without using WebSecurityConfigurerAdapter

Viewed 337

Prior to Spring Security 5.7 it was possible to add additional AuthenticationProviders to the global AuthenticationManager this way:

public class SecurityConfiguration extends WebSecurityConfigurerAdapter { 

    ...

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(customAuthenticationProvider);
    }

}

With Spring Security 5.7 the WebSecurityConfigurerAdapter was deprecated.

Question: ho should i migrate this code to solve the deprecation?

When i try to register the additional AuthenticationProvider as @Bean, the autocreated authentication provider for username/password based authentication gets replaced, leading to

No AuthenticationProvider found for org.springframework.security.authentication.UsernamePasswordAuthenticationToken

I read the blog post https://spring.io/blog/2022/02/21/spring-security-without-the-websecurityconfigureradapter but found no hints about adding additional authentication providers to the global AuthenticationManager.

4 Answers

If you have a single AuthenticationProvider you can register it as a bean and it will be picked up by Spring Security:

@Bean
public CustomAuthenticationProvider customAuthenticationProvider() {
    return new CustomAuthenticationProvider();
}

Alternatively, you can add additional AuthenticationProviders in the HttpSecurity configuration:

@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
    http
        // ...
        .authenticationProvider(new CustomAuthenticationProvider());
    return http.build();
}

You can annotate your configuration class with @EnableGlobalAuthentication and will be able to configure a global instance of AuthenticationManagerBuilder:

   @Autowired
   public void configureGlobal(AuthenticationManagerBuilder auth) {
      auth.authenticationProvider(customAuthenticationProvider);
   }

Please see the related documentation: https://docs.spring.io/spring-security/site/docs/current/api/org/springframework/security/config/annotation/authentication/configuration/EnableGlobalAuthentication.html

I had a same problem when I want to add an custom AuthenticationProvider using Spring Security without WebSecurityConfigurerAdapter.

Here is what I did.

Code with WebSecurityConfigurerAdapter

    public class SecurityConfiguration extends WebSecurityConfigurerAdapter { 

    ...

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(customAuthenticationProvider);
    }
    }

Code without WebSecurityConfigurerAdapter

@EnableWebSecurity
@EnableGlobalAuthentication
public class SecurityConfiguration { 
    
        ...

        @Autowired
        CustomAuthenticationProvider customAuthenticationProvider;

        @Autowired
        void registerProvider(AuthenticationManagerBuilder auth) {
           auth.authenticationProvider(customAuthenticationProvider);
        }
    }

Note: @EnableGlobalAuthentication and registerProvider().

Hope this will help.

I had a similar problem. I have a custom user details service and I also use an additional custom authentication provider. One is for actual users and the custom provider is for automated devices.

This is my code with the WebSecurityConfigurerAdapter:

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    ...

    @Autowired
    private MyCustomAuthenticationProvider customAuthenticationProvider;
  
    @Autowired
    private UserDetailsService userDetailsService;

    ...

    @Bean
    PasswordEncoder passwordEncoder() {
        return PasswordEncoderFactories.createDelegatingPasswordEncoder();
    }

    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    @Override
    public void configure(AuthenticationManagerBuilder auth) throws Exception {
        var encoder = passwordEncoder();
        customAuthenticationProvider.encoder(encoder);
        auth.userDetailsService(userDetailsService).passwordEncoder(encoder);
        auth.authenticationProvider(customAuthenticationProvider);
    }

    ...
}

This is my code without the WebSecurityConfigurerAdapter:

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

    @Autowired
    private MyCustomAuthenticationProvider customAuthenticationProvider;
  
    @Autowired
    private UserDetailsService userDetailsService;

    ...

    @Bean
    PasswordEncoder passwordEncoder() {
        return PasswordEncoderFactories.createDelegatingPasswordEncoder();
    }

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

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        var encoder = passwordEncoder();
        customAuthenticationProvider.encoder(encoder);
        auth.userDetailsService(userDetailsService).passwordEncoder(encoder);
        auth.authenticationProvider(customAuthenticationProvider);
    }

    ...

}

note: you might need to set spring.main.allow-circular-references to true in your properties file for this to work.

Related