Java – How Spring Security add/configure AuthenticationManagerBuilder

javaspring-security

I am working on Spring Security Java-based configuration.

I have created my own MyAuthenticationProvider which I want to register in the ProviderManager (single instance of AuthenticationManager).

I have found that ProviderManager has a list of providers to which I can register my single
MyAuthenticationProvider.

Here is the part of my Configuration:

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(MyAuthenticationProvider);
    }
}

I found out that AuthenticationManagerBuilder has parentAuthenticationManager, defaultUserDetailsService and many other fields.

My questions are:

  1. Where is this @Autowired annotation adding AuthenticationManagerBuilder auth from?
    Is the AuthenticationManagerBuilder already created in the application context?
  2. What would be the default state of AuthenticationManagerBuilder which is being injected? By default state I mean will there be some parentAuthenticationManager, authenticationProviders already registered in the AuthenticationManagerBuilder?
  3. If I am adding auth.authenticationProvider(MyAuthenticationProvider), does this mean that I am adding one more provider in the AuthenticationManagerBuilder?
  4. What does this mean? Taken from Spring Documentation

    The name of the configureGlobal method is not important. However, it
    is important to only configure AuthenticationManagerBuilder in a class
    annotated with either @EnableWebSecurity, @EnableWebMvcSecurity,
    @EnableGlobalMethodSecurity, or @EnableGlobalAuthentication. Doing
    otherwise has unpredictable results.

Best Answer

Answer for 1:

@EnableWebSecurity is meta-annotated with @EnableGlobalAuthentication

...
@EnableGlobalAuthentication
@Configuration
public @interface EnableWebSecurity {
...

and @EnableGlobalAuthentication imports AuthenticationConfiguration:

...
@Import(AuthenticationConfiguration.class)
@Configuration
public @interface EnableGlobalAuthentication {
}

In AuthenticationConfiguration, you'll see that an AuthenticationManagerBuilder bean is declared:

...
@Bean
public AuthenticationManagerBuilder authenticationManagerBuilder(
        ObjectPostProcessor<Object> objectPostProcessor, ApplicationContext context) {
    ...
}

When you @Autowire an AuthenticationManagerBuilder, this is the one that you will get. You have several methods at your disposal to easily configure in-memory, jdbc, ldap,... authentication.

Answer for 2:

Background:

The Spring Security Java config goes through several stages to seamlessly incorporate your configurations with the ApplicationContext.One place where this comes together is in the getHttp() method in WebSecurityConfigurerAdapter.

For example, this is an excerpt:

AuthenticationManager authenticationManager = authenticationManager();

authenticationBuilder.parentAuthenticationManager(authenticationManager);

To give you an idea of how "not-straightforward" the sequence of configuration is, the authenticationManager variable above will be either:

  • The authentication manager you added by overriding configure(AuthenticationManagerBuilder auth)
  • OR: The authentication manager you added in the method that @Autowired the AuthenticationManagerBuilder bean from AuthenticationConfiguration
  • OR: an AuthenticationManager bean found in the context

By default state I mean will there be some [...] authenticationProviders already registered in the AuthenticationManagerBuilder

If you look at AuthenticationConfiguration, you'll see that by default, the InitializeUserDetailsBeanManagerConfigurer is applied to the AuthenticationManagerBuilder bean. As long as it finds a UserDetailsService bean in the context and no other provider has been added, it will add a DaoAuthenticationProvider. This is why in the Spring Security reference, only providing a @Bean UserDetailsService bean is sufficient.

But once you add an authentication provider as you did, the "default" provider is not registered.