Jan Zyka
Jan Zyka

Reputation: 17898

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:

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 AuthenticationProviders 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.

Upvotes: 4

Views: 1334

Answers (1)

dur
dur

Reputation: 17010

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 ...
}

Upvotes: 2

Related Questions