14

I'm setting up my Spring Security (v4.0.1) web application. I want to have two authentication providers, an "in-memory" one to manage the administrator account and a custom one which refers to my own implementation. The system should attempt the authentication against the "in-memory" provider first of all and against the custom one in second place. My code looks like this:

@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth, 
    AuthenticationProvider provider) throws Exception {
    auth.inMemoryAuthentication()
            .withUser("admin")
            .password("s3cr3t")
            .authorities("ADMIN");
    auth.authenticationProvider(provider);
}

However, this code leads the framework to try my custom implementation first. It makes a bit of sense, since the AuthenticationManagerBuilder#authenticationProvider method adds a Provider to the internal List while the AuthenticationManagerBuilder#inMemoryAuthentication one configures it internally. How could I manage to get it work?

Aritz
  • 30,971
  • 16
  • 136
  • 217

3 Answers3

25

You can create your InMemoryUserDetailsManagerConfigurer manually and tell it to configure itself on the AuthenticationManagerBuilder when you have finished configuring it so it installs it's AuthenticationProvider before your custom one:

@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth,
        AuthenticationProvider provider) throws Exception {

    inMemoryConfigurer()
        .withUser("admin")
            .password("s3cr3t")
            .authorities("ADMIN")
        .and()
        .configure(auth);
    auth.authenticationProvider(provider);
}

private InMemoryUserDetailsManagerConfigurer<AuthenticationManagerBuilder>
        inMemoryConfigurer() {
    return new InMemoryUserDetailsManagerConfigurer<>();
}

Normally what happens is that the InMemoryUserDetailsManagerConfigurer is created and added to the list of configurers that should be applied when the AuthenticationManager is built - which is after you've installed your custom AuthenticationProvider.

Raniz
  • 10,882
  • 1
  • 32
  • 64
3

More or less from spring.io Documentation

If you are using XML configuration (e.g. spring-security.xml):

<security:authentication-manager>
    <security:authentication-provider ref="FirstProvider" />
    <security:authentication-provider ref="SecondProvider" />
</security:authentication-manager>

(I am using that setup for one of Spring's built-in authentication provider next to a custom one, works fine)

If you are using Java Config, I can only reference some other person's post maclema on Java config for multiple authentication provider, since I have never (successfully) tried code config

Community
  • 1
  • 1
user2039709
  • 890
  • 7
  • 17
  • Thanks for the answer, I'm not using the XML configuration. What I want to achieve is something similar to your linked answer, but instead of having two custom authentication providers, I've got a custom one and other in-memory one, which is provided by Spring. As the in-memory one is defined over the AuthenticationManagerBuilder, I don't know how to add it. – Aritz Jun 19 '15 at 09:58
0

Today we tend to configure Spring Security via WebSecurityConfigurerAdapter, you register filters that extract credentials from a request and register providers that use tokens built by filters by populating Authentication object with other details like authorities:

@Override
protected void configure(HttpSecurity http) throws Exception {
    AbstractPreAuthenticatedProcessingFilter tokenPreAuthProcessingFilter = new RequestHeaderAuthenticationFilter();
    http.addFilterAfter(tokenPreAuthProcessingFilter, SecurityContextPersistenceFilter.class);
}

@Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
    // First.
    auth.authenticationProvider(new PreAuthenticatedAuthenticationProvider());

    // Second.
    auth.inMemoryAuthentication()
            .passwordEncoder(NoOpPasswordEncoder.getInstance())
            .withUser(...);
}
gavenkoa
  • 45,285
  • 19
  • 251
  • 303