Using Custom Authentication Provider Spring Security

In this post we are going to find out why we need Custom Authentication Provider in Spring Security . Why do we need to implement this .

If You have  followed previous post about Flow of Authentication in Spring Security .

Spring Security has several areas where patterns you have defined are tested against incoming requests in order to decide how the request should be handled.

How Authentication Provider Flow Start 

This occurs when the FilterChainProxy decides which filter chain a request should be passed through and also when the FilterSecurityInterceptor decides which security constraints apply to a request.

Once it reaches the right authentication filter based on the authentication mechanism used ,  it extract the given credentials  from the request and then using the supplied values it creates the authentication object.

The it calls 'authenticate' method of the AuthenticationManager.

Now once Authentication manager tries to authenticate the request it  passes through the authentication providers to authenticate the user.

All the Authentication Providers inside spring security framework implement this interface .

Have a look at the Authentication Provider interface below :-

package org.springframework.security.authentication;

import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;

public interface AuthenticationProvider {
	Authentication authenticate(Authentication authentication)
			throws AuthenticationException;

	boolean supports(Class<?> authentication);
}

Now As you know for Writing a Custom Authentication provider in Spring Security , you basically should create your own implementation .

But Wait , Lets find out Why do we need a Custom Authentication Provider in Your Spring based applications by example .

Use Cases where we Need Custom Authentication Provider 

Lets say you are using authentication services provided by some third party in the form of Jar or an API.

In that case you can use the Spring Security Custom Authentication Provider to validate the username and password using the API . Once the validation is successful  we create the Authentication object and return to Spring Security framework.

Lets Implement a Custom Authentication Provider In Spring Security , by implementing Authentication Provider interface .

Lets Configure Spring Boot First before Configuring Custom Authentication Provider .

Configure Spring Security Configuration for Custom Provider 

package com.frugalis;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

@Configuration
@EnableWebSecurity
@ComponentScan("com.frugalis")
public class CustAuthProviderConfig extends WebSecurityConfigurerAdapter {
  
    @Autowired
    private CustomAuthenticationProvider authProvider;
 
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(authProvider);
    }
 
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests().anyRequest().authenticated()
            .and().httpBasic();
    }
}

The above code registers a custom authentication provider and authorize users .Now lets define a Custom Authentication Provider

package com.frugalis;

import java.util.ArrayList;
import java.util.List;

import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.User;
import org.springframework.stereotype.Component;

@Component
public class CustomAuthenticationProvider implements AuthenticationProvider {

	boolean shouldAuthenticateAgainstThirdPartySystem = true;

	@Override
	public Authentication authenticate(Authentication authentication) throws AuthenticationException {
		String name = authentication.getName();
		String password = authentication.getCredentials().toString();

		if (name.equals("admin") && password.equals("password")) {
			final List<GrantedAuthority> grantedAuths = new ArrayList<>();
			grantedAuths.add(new SimpleGrantedAuthority("ROLE_USER"));
			final UserDetails principal = new User(name, password, grantedAuths);
			final Authentication auth = new UsernamePasswordAuthenticationToken(principal, password, grantedAuths);
			return auth;
		} else {
			return null;
		}

	}

	@Override
	public boolean supports(Class<?> authentication) {

		return authentication.equals(UsernamePasswordAuthenticationToken.class);
	}

}

Code Explanation

In above code we have retrieved Username and password from the Authentication object . Once We retrieve the Authentication Object and Credentials , we are validating the username and password .

You can perform database based authentication , we have done a hard coded validation here .

Once user is valid we try and set GRANTED_AUTHORITY in list of String and return an UserDetails Object to the Caller an Authentication object . Instead of spring provided UserDetails , we can customize the User object set in principal and return .