Registration with Spring Security – Password Encoding

1. Overview

This article discusses a critical part of the registration process – password encoding – basically not storing the password in plaintext.

There are a few encoding mechanisms supported by Spring Security – and for the article, we’ll use BCrypt, as it’s usually the best solution available.

Most of the other mechanisms, such as the MD5PasswordEncoder and ShaPasswordEncoder use weaker algorithms and are now deprecated.

2. Define the Password Encoder

We’ll start by defining the simple BCryptPasswordEncoder as a bean in our configuration:

@Bean
public PasswordEncoder encoder() {
    return new BCryptPasswordEncoder();
}

Older implementations – such as SHAPasswordEncoder – would require the client to pass in a salt value when encoding the password.

BCrypt, however, will internally generate a random salt instead. This is important to understand because it means that each call will have a different result, and so we need to only encode the password once.

To make this random salt generation work, BCrypt will store the salt inside the hash value itself. For instance, in the following hash value:

$2a$10$ZLhnHxdpHETcxmtEStgpI./Ri1mksgJ9iDP36FmfMdYyVg9g0b2dq

There are three fields separated by $:

  1. The “2a” represents the BCrypt algorithm version
  2. The “10” represents the strength of the algorithm
  3. The “ZLhnHxdpHETcxmtEStgpI.” part is actually the randomly generated salt. Basically, the first 22 characters are salt. The remaining part of the last field is the actual hashed version of the plain text

Also, be aware that the BCrypt algorithm generates a String of length 60, so we need to make sure that the password will be stored in a column that can accommodate it. A common mistake is to create a column of a different length and then get an Invalid Username or Password error at authentication time.

3. Encode the Password on Registration

We will now use the PasswordEncoder in our UserService to hash the password during the user registration process:

Example 3.1. – The UserService Hashes the Password

@Autowired
private PasswordEncoder passwordEncoder;

@Override
public User registerNewUserAccount(UserDto accountDto) throws EmailExistsException {
    if (emailExist(accountDto.getEmail())) {
        throw new EmailExistsException(
          "There is an account with that email adress:" + accountDto.getEmail());
    }
    User user = new User();
    user.setFirstName(accountDto.getFirstName());
    user.setLastName(accountDto.getLastName());
    
    user.setPassword(passwordEncoder.encode(accountDto.getPassword()));
    
    user.setEmail(accountDto.getEmail());
    user.setRole(new Role(Integer.valueOf(1), user));
    return repository.save(user);
}

4. Encode the Password on Authentication

Let’s now handle the other half of this process and encode the password when the user authenticates.

First, we need to inject the password encoder bean we defined earlier into our authentication provider:

@Autowired
private UserDetailsService userDetailsService;

@Bean
public DaoAuthenticationProvider authProvider() {
    DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider();
    authProvider.setUserDetailsService(userDetailsService);
    authProvider.setPasswordEncoder(encoder());
    return authProvider;
}

The security configuration is simple:

  • we are injecting our implementation of the users details service
  • we are defining an authentication provider that references our details service
  • we are also enabling the password encoder

And finally, we need to reference this auth provider in our security XML configuration:

<authentication-manager>
    <authentication-provider ref="authProvider" />
</authentication-manager>

Or, in case you’re using Java configuration:

@Configuration
@ComponentScan(basePackages = { "com.maixuanviet.security" })
@EnableWebSecurity
public class SecSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(authProvider());
    }
    
    ...
}

5. Conclusion

This quick tutorial continues the Registration series by showing how to properly store the password in the database by leveraging the simple but very powerful BCrypt implementation.

The full implementation of this Registration with Spring Security tutorial can be found over on GitHub.

Related posts:

Feign – Tạo ứng dụng Java RESTful Client
Java Program to Implement ConcurrentLinkedQueue API
Simplify the DAO with Spring and Java Generics
Java Program to Generate Random Numbers Using Middle Square Method
Java Program to Implement Flood Fill Algorithm
Java Program to Implement Branch and Bound Method to Perform a Combinatorial Search
Java Program to Check Whether a Directed Graph Contains a Eulerian Path
Hướng dẫn Java Design Pattern – Composite
Constructor Injection in Spring with Lombok
Spring REST with a Zuul Proxy
Java Program to Implement Sparse Array
Java Program to Find SSSP (Single Source Shortest Path) in DAG (Directed Acyclic Graphs)
Giới thiệu luồng vào ra (I/O) trong Java
Java Web Services – JAX-WS – SOAP
Java Program to Solve the Fractional Knapsack Problem
Java Program to Use Boruvka’s Algorithm to Find the Minimum Spanning Tree
Java Program to Implement Min Hash
Java Program to Implement Sieve Of Atkin
Introduction to PCollections
Lớp LinkedHashMap trong Java
Removing Elements from Java Collections
Hướng dẫn sử dụng String Format trong Java
Java Program to Implement Gale Shapley Algorithm
Reactive Flow with MongoDB, Kotlin, and Spring WebFlux
JPA/Hibernate Persistence Context
Java Program to Solve Set Cover Problem assuming at max 2 Elements in a Subset
OAuth2.0 and Dynamic Client Registration
Java Program to Implement Ternary Search Algorithm
The SpringJUnitConfig and SpringJUnitWebConfig Annotations in Spring 5
Dockerizing a Spring Boot Application
Write/Read cookies using HTTP and Read a file from the internet
Hướng dẫn Java Design Pattern – State