Spring Security – Customize Authentication Provider

In the post, we guide how to customize AuthenticationProvider for SpringSecurity web application.

I. Technology

– Apache Maven 3.5.2
– Spring Tool Suite – Version 3.9.0.RELEASE
– Spring Boot – 1.5.10.RELEASE
– Bootstrap

II. SpringSecurity Authentication Provider

SpringSecurity provides an interface to customize Authentication:

public interface AuthenticationProvider{
	Authentication authenticate(Authentication authentication)
			throws AuthenticationException;
	
	--> Performs authentication with the same contract as AuthenticationManager.authenticate(Authentication).
	
	boolean supports(Class authentication);
	
	--> Returns 'true' if this AuthenticationProvider supports the indicated Authentication object.
}
Goal

Create a Kotlin SpringBoot project as below:

spring security - customize authentication provider - project structure

Login page:

springsecurity-authentication-provider-login-page-1

When login with accounts: {user/user, admin/admin} -> login successfully

-> console’s logs:

INFO c.j.s.k.c.CustomAuthenticationProvider   : Succesful Authentication with user = admin!
INFO c.j.s.k.c.CustomAuthenticationProvider   : Succesful Authentication with user = user!

When login with others, example {peter/peter} -> login fail

-> console’s logs:

ERROR c.j.s.k.c.CustomAuthenticationProvider   : Authentication failed for user = peter

springsecurity-authentication-provider-fail-authentiaction
III. Implementation

Step to do
– Create Kotlin SpringSecurity project
– Customize Authentication Provider

1. Create Kotlin SpringSecurity project

-> Follow the article: SpringBoot – Configure Spring Security

2. Customize Authentication Provider

– CustomAuthenticationProvider:

package com.javasampleapproach.springsecurity.authenticationprovider.config;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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.stereotype.Component;

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

import javax.annotation.PostConstruct;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.authentication.BadCredentialsException;

@Component
public class CustomAuthenticationProvider implements AuthenticationProvider {

	private Logger logger = LoggerFactory.getLogger(this.getClass());
	List users = new ArrayList();

	@PostConstruct
	void init() {
		users.add(new User("user", "user", "ROLE_USER"));
		users.add(new User("admin", "admin", "ROLE_ADMIN"));
	}

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

		Optional optionalUser = users.stream().filter(u -> u.index(name, password)).findFirst();

		if (!optionalUser.isPresent()) {
			logger.error("Authentication failed for user = " + name);
			throw new BadCredentialsException("Authentication failed for user = " + name);
		}

		// find out the exited users
		List grantedAuthorities = new ArrayList();
		grantedAuthorities.add(new SimpleGrantedAuthority(optionalUser.get().role));
		UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(name, password,
				grantedAuthorities);

		logger.info("Succesful Authentication with user = " + name);
		return auth;
	}

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

	private class User {
		String name;
		String password;
		String role;

		User(String name, String password, String role) {
			this.name = name;
			this.password = password;
			this.role = role;
		}

		boolean index(String name, String password) {
			return this.name.equals(name) && this.password.equals(password);
		}
	}
}

– Configure ‘CustomAuthenticationProvider’ bean in ‘WebSecurityConfigurer’

package com.javasampleapproach.springsecurity.authenticationprovider.config;

import org.springframework.beans.factory.annotation.Autowired;
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.WebSecurityConfigurerAdapter;
 
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
	@Autowired
	private CustomAuthenticationProvider authProvider;
 
	@Override
	protected void configure(HttpSecurity http) throws Exception {
		http.authorizeRequests().antMatchers("/", "/home").permitAll().antMatchers("/admin").hasRole("ADMIN")
				.anyRequest().authenticated().and().formLogin().loginPage("/login").permitAll().and().logout()
				.permitAll();
		http.exceptionHandling().accessDeniedPage("/403");
	}
 
	@Override
	protected void configure(AuthenticationManagerBuilder auth) throws Exception {
		auth.authenticationProvider(authProvider);
	}
}

IV. Sourcecode

SpringSecurityCustomizeAuthenticationProvider



By grokonez | December 10, 2016.

Last updated on March 8, 2018.



Related Posts


4 thoughts on “Spring Security – Customize Authentication Provider”

  1. This example works fine if I use login form. But what if I need not it?
    If I use configure like this :

        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.authorizeRequests()
                    .antMatchers("/public").permitAll()
                    .antMatchers("/private").hasRole(ADMIN)
                    .antMatchers("/**").permitAll()
                    .anyRequest().authenticated();
        }
    

    CustomAuthenticationProvider method authenticate(…) did not used at all (use debug to confirm) and page are always forbidden when trying to access /admin resource

    1. Hi,

      If you don’t need a login page, Are you working with httpBasic?
      -> If Yes, you can try the segment code for httpBasic security:

      protected void configure(HttpSecurity http) throws Exception {
              http
               [...]
      
               .and()
               .httpBasic();
          }
      [...]
      

      More details, you can try the tutorial:
      How to configure Spring RestTemplate Security

      Regards,
      JSA

  2. hi aykytakin,
    I need to integrate my own authentication which takes in username password and returns true or false in return.Can this be included in the the customAuthenticationProvider? I have a web app which needs spring web security integration. Please help as i am new to spring concepts. Also the roles will be provided against a usernames which will be present in a text file name=role.
    Can u please give a head start to implement such requirement.

  3. How can we customize the exception thrown by AuthenticationProvider implementation class, in my my own Error code/Description response ?

Got Something To Say:

Your email address will not be published. Required fields are marked *

*