Spring Security password hashing example

In this tutorial, we will show you how to use BCryptPasswordEncoder to hash a password and perform a login authentication in Spring Security.

In the old days, normally, we used MD5 Md5PasswordEncoder or SHA ShaPasswordEncoder hashing algorithm to encode a password… you are still allowed to use whatever encoder you like, but Spring recommends to use BCrypt BCryptPasswordEncoder, a stronger hashing algorithm with randomly generated salt.

Technologies used :

  1. Spring 3.2.8.RELEASE
  2. Spring Security 3.2.3.RELEASE
  3. Spring JDBC 3.2.3.RELEASE
  4. MySQL Server 5.6

1. Review PasswordEncoder

The familiar old authentication PasswordEncoder interface is deprecated…


package org.springframework.security.authentication.encoding;

//Implementation : Md5PasswordEncoder and ShaPasswordEncoder
@Deprecated
public interface PasswordEncoder {

Instead, you should use this new crypto PasswordEncoder interface.


package org.springframework.security.crypto.password;

//Implementation : BCryptPasswordEncoder
public interface PasswordEncoder {

2. Generate a BCrypt Password

First, hash a password and put it into a database, for login authentication later. This example uses BCryptPasswordEncoder to hash a password “123456”.

PasswordEncoderGenerator.java

package com.mkyong.web.controller;

import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

public class PasswordEncoderGenerator {

  public static void main(String[] args) {

	int i = 0;
	while (i < 10) {
		String password = "123456";
		BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
		String hashedPassword = passwordEncoder.encode(password);

		System.out.println(hashedPassword);
		i++;
	}

  }
}

In BCrypt hashing algorithm, each time, a different hash value of length 60 is generated.


$2a$10$EblZqNptyYvcLm/VwDCVAuBjzZOI7khzdyGPBr08PpIi0na624b8.
$2a$10$trT3.R/Nfey62eczbKEnueTcIbJXW.u1ffAo/XfyLpofwNDbEB86O
$2a$10$teJrCEnsxNT49ZpXU7n22O27aCGbVYYe/RG6/XxdWPJbOLZubLIi2
$2a$10$BHG59UT6p7bgT6U2fQ/9wOyTIdejh4Rk1vWilvl4b6ysNPdhnViUS
$2a$10$W9oRWeFmOT0bByL5fmAceucetmEYFg2yzq3e50mcu.CO7rUDb/poG
$2a$10$HApapHvDStTEwjjneMCvxuqUKVyycXZRfXMwjU0rRmaWMsjWQp/Zu
$2a$10$GYCkBzp2NlpGS/qjp5f6NOWHeF56ENAlHNuSssSJpE1MMYJevHBWO
$2a$10$gwbTCaIR/qE1uYhvEY6GG.bNDQcZuYQX9tkVwaK/aD7ZLPptC.7QC
$2a$10$5uKS72xK2ArGDgb2CwjYnOzQcOmB7CPxK6fz2MGcDBM9vJ4rUql36
$2a$10$6TajU85/gVrGUm5fv5Z8beVF37rlENohyLk3BEpZJFi6Av9JNkw9O

It's normal to get a different value each time you hash a value with BCrypt, because salt is generated randomly. In this tutorial, we get the first output and inserts it into the database.

3. Database

Create tables and insert a user "mkyong" for testing.


CREATE  TABLE users (
  username VARCHAR(45) NOT NULL ,
  password VARCHAR(60) NOT NULL ,
  enabled TINYINT NOT NULL DEFAULT 1 ,
  PRIMARY KEY (username));

CREATE TABLE user_roles (
  user_role_id int(11) NOT NULL AUTO_INCREMENT,
  username varchar(45) NOT NULL,
  role varchar(45) NOT NULL,
  PRIMARY KEY (user_role_id),
  UNIQUE KEY uni_username_role (role,username),
  KEY fk_username_idx (username),
  CONSTRAINT fk_username FOREIGN KEY (username) REFERENCES users (username));

INSERT INTO users(username,password,enabled)
VALUES ('mkyong','$2a$10$EblZqNptyYvcLm/VwDCVAuBjzZOI7khzdyGPBr08PpIi0na624b8.', true);

INSERT INTO user_roles (username, role)
VALUES ('mkyong', 'ROLE_USER');
INSERT INTO user_roles (username, role)
VALUES ('mkyong', 'ROLE_ADMIN');

4. Enable Password Encoder

A few ways to enable the password encoder in XML configuration.

4.1 Using the default BCryptPasswordEncoder.

spring-security.xml

  <authentication-manager>
	<authentication-provider>
	    <password-encoder hash="bcrypt" />
	</authentication-provider>
  </authentication-manager>

4.2 Pass a "strength" parameter to the BCryptPasswordEncoder.

spring-security.xml

  <authentication-manager>
	<authentication-provider>
	    <password-encoder ref="encoder" />
	</authentication-provider>
  </authentication-manager>
	
  <beans:bean id="encoder" 
	class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder">
	<beans:constructor-arg name="strength" value="11" />
  </beans:bean>

4.3 Pass an encoder to DaoAuthenticationProvider.

spring-security.xml

  <bean id="authProvider" 
	class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
	<property name="userDetailsService" ref="customUserService" />
	<property name="passwordEncoder" ref="encoder" />
  </bean>

  <bean id="encoder" 
	class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder"/>

4.4 Annotation example.


@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

	@Autowired
	DataSource dataSource;
	
	@Autowired
	public void configAuthentication(AuthenticationManagerBuilder auth) 
		throws Exception {
		
		auth.jdbcAuthentication().dataSource(dataSource)
			.passwordEncoder(passwordEncoder())
			.usersByUsernameQuery("sql...")
			.authoritiesByUsernameQuery("sql...");
	}	
	
	@Bean
	public PasswordEncoder passwordEncoder(){
		PasswordEncoder encoder = new BCryptPasswordEncoder();
		return encoder;
	}

5. Project Demo

Access a password protected page : localhost:8080/spring-security-password-hashing/admin, a login page is displayed. Enter a password "123456", Spring Security will hash the password and compare it with the hashed password from database.

spring-security-password-encoder

User and password in Database.

spring-security-password-encoder-database

Download Source Code

References

  1. Wikipedia : Bcrypt
  2. BCryptPasswordEncoder JavaDoc
  3. Spring Security Reference : Password Encoder

About the Author

author image
mkyong
Founder of Mkyong.com, love Java and open source stuff. Follow him on Twitter, or befriend him on Facebook or Google Plus. If you like my tutorials, consider make a donation to these charities.

Comments

avatar
20 Comment threads
14 Thread replies
1 Followers
 
Most reacted comment
Hottest comment thread
28 Comment authors
MnariosAndres AusechaJoshSudharsanGreg Havener Recent comment authors
newest oldest most voted
Vipin Nair
Guest
Vipin Nair

If I have to disallow a user from setting a password, which they had used in the last 5 instances, would I be able to do that?

Greg Havener
Guest
Greg Havener

Yes, you will just need to save the last five passwords, then when the user sets a new one compare it against all of the old ones using BCryptPasswordEncoder.matches() passing in the newly hashed password and each saved hashed password.

Ivan Masli
Guest
Ivan Masli

What is the purpose of these method? an what “sql. . .” means?

.usersByUsernameQuery(“sql…”)
.authoritiesByUsernameQuery(“sql…”);

Mnarios
Guest
Mnarios

how can I run this project?
the files above are separated or we should use them?

Andres Ausecha
Guest
Andres Ausecha

mkyong You have been saving my inexpert ass since years ago…but this is the first time i thank you, your java tutorials always help to find the right answer.

Josh
Guest
Josh

For anyone wondering where the salt value is or how this works, the top answer here explains it well:
https://stackoverflow.com/questions/6832445/how-can-bcrypt-have-built-in-salts

Sudharsan
Guest
Sudharsan

Hi Thanks. How does the decode works here?

Jack Parker
Guest
Jack Parker

If I wanted to store the password between two columns (as in a hash and salt column), how would you recommend doing that?

HEILEEN GOODSON
Guest
HEILEEN GOODSON

Hi, y try to look for decode md5 and i cant found it, i have a bean whit a password in md5 but i have to decode and i can Y_Y, can any help me?

superwoodoo
Guest
superwoodoo

MD5 cannot be decoded. It is a one-way encoding (hash code)

Aman
Guest
Aman

Is it possible to call a user defined hash function, that is defined in the oracle database?

Sachin
Guest
Sachin

I generated 10 different encrypted password for 123456 and each of them worked for me. How is it possible?

Narendra
Guest
Narendra

What if a user wants to retrieve his original password. i mean if he forgets his password, he will request for his original(non-encrypted) password, but there is no way we can decrypt it. so does that mean, we sud not use bcrypt in that situation and go or for some other algorithm, if so then which algorithm is best suitable in this situation.

raprav
Guest
raprav

I think the best choice is to allow user to set a new password through a mailed link. I think storing decryptable passwords this way is not secure nor ethic.

Dimash
Guest
Dimash

Hello mkyong,

nice tutorial so far! I have a simple question: When I want to exchange the bcrypt encoder against a sha256+salt encoder, what do I have to do?
I replaced the bcrypt bean implementation against this implementation:
@Bean
public ShaPasswordEncoder passwordEncoder(){
ShaPasswordEncoder encoder = new ShaPasswordEncoder(256);
return encoder;
}
Now, how can I add salt to that?

Greets
Dimash

dan
Guest
dan

i love you mkyong

ololoepepe
Guest
ololoepepe

Well, but the password is POSTed in non-encripted form, isn’t it? (Just as it is by default.) So what are the advantages of your approach?

mkyong
Guest
mkyong

To post the password in encrypted form, make your web server to use HTTPS.

The advantages

1. Your password will not be compromise if the database is hacked. because there is no way (very hard) to revert back to the original password.
2. No one know the user’s password, even the database administrator.

AN
Guest
AN

When importing into eclipse have following error, doesnot compile in maven, any suggestions to fix error,ERROR is:”An internal error occurred during: “Importing Maven projects”. Unsupported IClasspathEntry kind=4″?

Sourav Ken
Guest
Sourav Ken

I usually delete
1) .project
2) .classpath
3) .settings
and then I will import the in eclipse as maven project. This usually solve this problem you facing now.

Vivek Agrawal
Guest
Vivek Agrawal

if each time a different hash value is generated for the same password. then how can one password can be compared to one of its generated hash value?

mkyong
Guest
mkyong

Each time, it will hash to same value for same password. Study hash algorithm from http://en.wikipedia.org/wiki/Hash_function

mkyong
Guest
mkyong

With BCrypt encoder, you don’t need to worry about the random generated SALT value, the generated hash value you see above will NOT be use to compare directly with the database hash value, BCrypt algorithm still need to do extra “things” to make sure it match.

I’m not really sure how exactly BCrypt algorithm works, if you are interest, do study below Spring Security classes , get the source code and read the complicated algorithm :)

1. BCryptPasswordEncoder.java
2. BCrypt.java

Here’s the wiki link
1. http://en.wikipedia.org/wiki/Bcrypt

komar
Guest
komar

I’m not really sure how this algorithm is implemented this is logical:
salt is generated randomly, and at the end it’s concatenated to main
hash. It’s simple and it works.

Kevin
Guest
Kevin

BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();

encoder.matches(password, user.getPassword());

password – from form(JSP)

user.getPassword() – from database

Markus Mahlberg
Guest
Markus Mahlberg

The SHA algorithm should not be considered secure. Xiaoyun Wang, Yiqun Lisa Yin, and Hongbo Yu did the cryptanalysis and Bruce Schneier explained it in his “Schneier on Security”-Blog (http://bit.ly/14L0ImQ).

So please: If security is really a concern and you are not absolutely positively sure that SHA-1 fulfills you security needs, use SHA-256 instead.

Bottom line: if you do not need to create thousands of hashes a second, you should always use SHA-256, despite the fact that it is slower than SHA-1.

mkyong
Guest
mkyong

Thanks, article is updated to use Bcrypt.

Anand
Guest
Anand

Hi mkyong, I’m a big fan of you and your tutorials. Believe it or not, I landed with this page searching for http://bit.ly/13U3d7D :)

Ok, this application works like a charm, but my question is :

Is there any way to add a salt to our password this way, the hard-coding-credentials-in-xml way? I’m just going to hard code few username and passwords in the xml. I don’t want to get into setting up a DB datasource for this purpose.

mkyong
Guest
mkyong

Article is updated, yes you can do that.

salish
Guest
salish

hi <authentication-manager> <authentication-provider> <password-encoder hash="sha" /> <user-service> <user name="mkyong" password="7c4a8d09ca3762af61e59520943dc26494f8941b" authorities="ROLE_USER" /> </user-service> </authentication-provider> </authentication-manager> in spring how to use custom password decoding .in my applicationcontext-security.xml file i used <authentication-manager alias="authenticationManager"> <authentication-provider user-service-ref="customUserDetailsService"> </authentication-provider> </authentication-manager> and customUserDetailsService is a bean id with class that implements UserDetailsService there in loadUserByUsername method i use coustom password endoder.but while running the project in neatbeans i got the error Exception while loading the app : java.lang.IllegalStateException: ContainerBase.addChild: start: org.apache.catalina.LifecycleException: org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘org.springframework.security.authentication.ProviderManager#0’: Cannot create inner bean ‘(inner bean)’ of type [org.springframework.security.config.authentication.AuthenticationManagerFactoryBean] while setting bean property ‘parent’; nested exception is org.springframework.beans.factory.BeanCreationException:… Read more »

ohad
Guest
ohad

you should not have 2 authentication managers.

Sachin
Guest
Sachin

Hello,
I have not tried it yet but,does the decryption happen internally while checking for authentication?

Thanks

ohad
Guest
ohad

AFAIK, there is no decryption. u save the password in the DB encrypted, and when the user enters his pswd, Spring encrypts it and compares to what u have in the DB.
HTH
Ohad

trackback
Spring Security form login example (authentication)

[…] you should always hash the password with SHA or MD5 algorithm, this tutorial show you how – Spring Security password hashing example.3. Spring MVC ControllerSpring controller to handle what URL should go where. Note You may interest […]