Jan Zyka Jan Zyka - 3 months ago 50
Java Question

WebSecurityConfigurerAdapter with custom authentication filter - dependency issue

I have spring security configuration with SPNEGO which is working "with a hack". It looks as follows:

@Configuration
@EnableWebSecurity
public class SpnegoConfig extends WebSecurityConfigurerAdapter {

@Override
protected void configure(HttpSecurity http) throws Exception {
http
...
.addFilterBefore(
spnegoAuthenticationProcessingFilter(authenticationManagerBean()),
BasicAuthenticationFilter.class); // 1
}

@Override
@Autowired // 3
protected void configure(AuthenticationManagerBuilder auth)
throws Exception {
auth
.authenticationProvider(kerberosAuthenticationProvider())
.authenticationProvider(kerberosServiceAuthenticationProvider());
}


@Bean
public SpnegoAuthenticationProcessingFilter spnegoAuthenticationProcessingFilter(
AuthenticationManager authenticationManager) { // 2
SpnegoAuthenticationProcessingFilter filter =
new SpnegoAuthenticationProcessingFilter();
filter.setAuthenticationManager(authenticationManager);
return filter;
}
...
}


What is happening:


  • I need to add spnegoAuthenticationProcessingFilter (1)

  • This filter has dependency on authenticationManager (2)

  • I need to add authentication providers (3)



Point being in this class which is
WebSecurityConfigurerAdapter
I'm overriding 2 methods:


  1. configure(HttpSecurity http)
    - this has dependency on the already built
    AuthenticationManager
    through custom filter

  2. configure(AuthenticationManagerBuilder auth)
    - this clearly relates on
    AuthenticationManager
    no being built yet - we're building it



If I don't have the
@Autowired
on method (3) the
AuthenticationManager
is built too early and my adding of
AuthenticationProvider
s has no effect. The authentication fails with exception there is no suitable
AuthenticationProvider
.

With the
@Autowired
in place it works but if feels wrong. I'm not even sure why it starts working then.

Please advice on the right approach.

Edit: It actually works without the @Autowired. But the point is in the accepted answer. If you ever depend on
AuthenticationManager
in
@Configuration
make sure it's either exposed or referenced via the
authenticationManagerBean()
method.

dur dur
Answer

You use the wrong AuthenticationManager.

If you want to use the AuthenticationManager from SpnegoConfig with dependency injection, you have to expose it, see JavaDoc:

Override this method to expose the AuthenticationManager from configure(AuthenticationManagerBuilder) to be exposed as a Bean. For example:

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

If you want to configure global AuthenticationManager, you have to autowire the AuthenticationMangerBuilder, see Spring Security 3.2.0.RC2 Released

For example, if you want to configure global authentication (i.e. you only have a single AuthenticationManager) you should autowire the AuthenticationMangerBuilder:

@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) {
   // ... configure it ...
}
Comments