Spring Security Multiple Authentication Providers

In this article, we will take a look at the Spring Security multiple authentication providers. We will see how to configure and use multiple authentication provider in your application. This article is part of our Spring security tutorial.

Spring Security Multiple Authentication Providers

AuthenticationProviders are the core workers in Spring security. They are responsible for fetching the user information based on the provider configuration. e.g.

  • DAOAuthenticationProvider is responsible for getting user information from the database using the UserDetailService.
  • LDAP works by loading information from the LDAP.

There are many use cases where we may want to configure multiple AuthenticationProviders in our application. Spring Security provides a flexible way to configure multiple AuthenticationProviders. When multiple providers are configured for our application, they will be queries in the order they are configured. Here is a high level authentication workflow to refresh your memory.

spring security authentication provider
Spring Security Multiple Authentication Providers

1. Custom Authentication Provider

To demonstrate Spring Security multiple authentication providers capabilities, we will be configuring the DAOAutehtnicationProvider and a custom authentication provider. Let’s see how the custom authentication provider look like:

package com.javadevjournal.core.security.authentication.provider;


import org.apache.commons.lang3.StringUtils;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;

@Component
/**
 * <p>A custom Authentication provider example. To create custom AuthenticationProvider, we need to implement the
 * AuthenticationProvider provide the implementation for the authenticate and support method.</p>
 */
public class CustomAuthenticationProvider implements AuthenticationProvider {

    @Resource
    UserDetailsService userDetailsService;

    /**
     * <p> The authenticate method to authenticate the request. We will get the username from the Authentication object and will
     * use the custom @userDetailsService service to load the given user.</p>
     * @param authentication
     * @return
     * @throws AuthenticationException
     */
    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        final String username = (authentication.getPrincipal() == null) ? "NONE_PROVIDED" : authentication.getName();
        if (StringUtils.isEmpty(username)) {
            throw new BadCredentialsException("invalid login details");
        }
        // get user details using Spring security user details service
        UserDetails user = null;
        try {
            user = userDetailsService.loadUserByUsername(username);

        } catch (UsernameNotFoundException exception) {
            throw new BadCredentialsException("invalid login details");
        }
        return createSuccessfulAuthentication(authentication, user);
    }

    private Authentication createSuccessfulAuthentication(final Authentication authentication, final UserDetails user) {
        UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(user.getUsername(), authentication.getCredentials(), user.getAuthorities());
        token.setDetails(authentication.getDetails());
        return token;
    }

    @Override
    public boolean supports(Class << ? > authentication) {
        return authentication.equals(UsernamePasswordAuthenticationToken.class);
    }
}

Read read Spring Security Custom Authentication Provider for more details on the custom authentication provider in Spring security.

2. Configuring Multiple Authentication Providers

The next step is to configure these multiple authentication provider in our Spring security application. We will be using the Java configuration for this. We will use the AuthenticationManagerBuilder to create and add authentication providers for our application. This is how the configuration look like:

@EnableWebSecurity
public class AppSecurityConfig extends WebSecurityConfigurerAdapter {

    @Resource
    UserDetailsService userDetailsService;


    @Resource
    private CustomAuthenticationProvider customAuthenticationProvider;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        ....
    }


    /**
     * DAO authentication provider. This authentication provider will authenticate the user with the help of
     * @UserdetailsService. This is based on the validating the user with the username and password.
     * @return
     */
    @Bean
    public DaoAuthenticationProvider authProvider() {
        DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider();
        authenticationProvider.setPasswordEncoder(passwordEncoder);
        authenticationProvider.setUserDetailsService(userDetailsService);
        return authenticationProvider;
    }

    /**
     * Authentication manager which will be invoked by Spring security filter chain. This authentication
     * manager will delegate the work to the Authentication provider to
     * authenticate the user. Look out for the @DaoAuth provider in the above section to see
     * how it works with this.
     * @param auth
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) {
        auth.authenticationProvider(authProvider())
            .authenticationProvider(customAuthenticationProvider);
    }
}

3. Testing Application

The source code for this article is available on our GitHub Repository, you can download the code to run the application. To test the Spring Security multiple authentication providers and their workflow, let’s run our application and use a simple REST client to test the login feature. As mentioned earlier, When multiple providers are configured for our application, they will be queries in the order they are configured. In our case, the DaoAuthenticationProvider is configured first and it will be called first by system. Here is how the it look like:

Spring Security Multiple Authentication Providers
Spring Security Multiple Authentication Providers

Spring Won’t use more than one AuthenticationProvider to authenticate the request.AuthenticationProvider that support the Authentication object and successfully authenticate the request will be the only one used. Don’t expect that all AuthenticationProvider will be executed by Spring.

Let’s change the configuration of the authentication provider and see if our custom provider is triggered first.

@Override
protected void configure(AuthenticationManagerBuilder auth) {
    auth.authenticationProvider(customAuthenticationProvider)
        .authenticationProvider(authProvider());
}
Spring Security Multiple Authentication Providers
Spring Security Multiple Authentication Providers

As you can see when we changed the configuration sequence for our multiple authentication providers, our custom AuthenticationProvider was triggered by Spring Security. This was a simple example, please keep in mind the following important points:

  1. We need multiple AuthenticationProviders when we have different authentication need e.g need DAOAuthenticationProvider for DB based authentication but a TokenAuthenticationProvider for token bases authentication.
  2. We don’t want to use 2 different AuthenticationProviders which support same kind of token (remember each AuthenticationProvider method have support method which tell what kind of authentication is supported by given provider).
  3. In case your authentication provider support same kind of authentication as offered by Spring OOTB provider, you should always think of extending the OOTB provider than creating custom one.

There are requirements where we want to configure and use different AuthenticationProviders based on the URL pattern (e.g. /api/** should use TokenAuthenticationProvider). In the next article, we will take a look at these kind of requirements.

Summary

In this article, we take a look at the Spring Security multiple authentication providers. We saw how to configure and use multiple provider with our Spring security application.