Password security is a popular topic. The most basic tenant of password security is to have no password at all. Wait, what? That’s right, no password should be stored in your database, ever. Instead, store it as a hash, along with the salt, and throw the original password away. Ask 10 different developers, and I’ll bet that MD5 would be offered as the most popular solution for this problem. Though, if you’ve explored the linked content, you’ll have undoubtedly noticed that Bcrypt is mentioned more than a few times.
“Bcrypt is a cross platform file encryption utility. Encrypted files are portable across all supported operating systems and processors. Passphrases must be between 8 and 56 characters and are hashed internally to a 448 bit key. However, all characters supplied are significant. The stronger your passphrase, the more secure your data.”
For us Java developers, there’s jBCrypt. It is an “implementation of OpenBSD’s Blowfish password hashing code” and offers a rather simple API. A quick web search yields a bit of information on using jBCrypt itself, but nothing on integrating it with the Spring Framework. Given that this is a topic of interest to me, I’ve put together a simple, yet comprehensive example web application to demonstrate an integration of jBCrypt, Spring MVC, Spring Security and Hibernate for hashing user passwords. There are three areas I’ve focused on in this example, user creation, user authentication and changing the user’s password.
Unlike other solutions, jBCrypt is surprisingly easy to use. When a new user registers for our simple application, the password is hashed using BCrypt.hashpw(rawPass, salt). You, the developer, are given a choice of providing a salt or generating a random salt with BCrypt.gensalt(). I’ve chosen to use a random salt for each hash, increasing the strength of the solution. Here’s a look at the code responsible for creating the new User object.
JoinController.java
@Controller
public class JoinController {
...
@RequestMapping(value = "/join.do", method = RequestMethod.POST)
public String processSubmit(@ModelAttribute("form") JoinForm form, BindingResult result) {
logger.debug("Processing join form.");
new JoinFormValidator().validate(form, result);
if (!result.hasErrors()) {
User user = new User(
form.getUsername(),
BCrypt.hashpw(form.getPassword(), BCrypt.gensalt()),
form.getEmail());
service.create(user);
return "join-success";
}
return "join";
}
...
}
The astute observer might note that I could have used a Hibernate Interceptor to hash the password when the User is inserted into the database. And while that is a valid solution, I prefer to get rid of the original password sooner and keep the hashing routine along side the User creation code.
User authentication with Spring Security needs to use a PasswordEncoder implementation to hash and validate the supplied password. This is straight forward to do as is demonstrated in the example application.
BCryptPasswordEncoder.java
public class BCryptPasswordEncoder implements PasswordEncoder {
public String encodePassword(String rawPass, Object salt) throws DataAccessException {
logger.debug("Encoding password.");
return BCrypt.hashpw(rawPass, BCrypt.gensalt());
}
public boolean isPasswordValid(String encPass, String rawPass, Object salt) throws DataAccessException {
logger.debug("Validating password.");
return BCrypt.checkpw(rawPass, encPass);
}
}
As you can see, there really isn’t much to this. You’ll need to instruct Spring Security to use your PasswordEncoder by adding a bean definition and dependency to your context configuration file.
spring-security.xml
<authentication-provider user-service-ref="userService">
<password-encoder ref="passwordEncoder"/>
</authentication-provider>
<beans:bean id="passwordEncoder" class="net.sziebert.tutorials.security.BCryptPasswordEncoder"/>
Changing the user’s password is no different, though it does have two parts to get it right. Because we require the user to supply their original password before updating it, we need to insure the input is correct.
ChangePasswordFormValidator.java
public class ChangePasswordFormValidator implements Validator {
...
public void validate(Object obj, Errors errors) {
logger.debug("Validating change password form.");
ChangePasswordForm form = (ChangePasswordForm) obj;
...
// Insure the specified original password actually matches the performer's current password.
if (isNotBlank(form.getPassword())) {
if (!BCrypt.checkpw(form.getOriginal(), user.getPassword())) {
errors.rejectValue("original", "error.original.password.mismatch");
}
}
}
}
Once the original validates correctly, we can then update the database with the a new hash. Like the previous examples, this is trivial to accomplish.
ChangePasswordController.java
@Controller
public class ChangePasswordController {
...
@RequestMapping(value = "/password.do", method = POST)
public String processSubmit(HttpServletRequest request,
@ModelAttribute("form") ChangePasswordForm form,
BindingResult result) {
logger.debug("Processing change password form.");
User user = service.findByUsername(getCurrentUsername());
new ChangePasswordFormValidator(user).validate(form, result);
if (!result.hasErrors()) {
user.setPassword(BCrypt.hashpw(form.getPassword(), BCrypt.gensalt()));
service.update(user);
request.getSession().setAttribute("message", "You have successfully changed your password.");
return "redirect:/home.do";
}
return "change-password";
}
...
}
As with all of my posts, I invite you to download the example application and give it a try. Make sure that you’ve got all of the dependencies and have compiled the source by running ant compile. Let me know if you’ve got questions or feedback.
The example source code for this post can be downloaded here.
Carl Sziebert is a loving husband, devoted father, and accomplished software engineer, living and working in the San Francisco Bay Area. He is no stranger to code, having spent the better part of a decade developing software for a diverse range of organizations, including small startups, large corporations, and government agencies. Having built a solid foundation of skills from these experiences, Carl now works as an engineer at 





4 Comments
i use it like that.
but instead of having the hashing code spread to every form. just inject the passwordencoder and use the encodePassword method.
That way you can change it later on if needed without having to find all places where a password get’s hashed.
Carl,
So, I’m googling BCrypt and Spring, and your post came up. We’re using this stuff too. Small world! Hope you, the kids, and wife, are well.
Jason
Hey Jason!
Thanks for leaving a comment! I’m in the process of adding some additional functionality around password reset to the example. If you’ve got any suggestions for improving or adding to what I’ve got, please let me know.
I submitted a feature request for adding built-in bcrypt support to Spring Security: https://jira.springsource.org/browse/SEC-1472