VOOZH about

URL: https://www.javacodegeeks.com/2014/01/automatically-converting-password-hashes-in-grails-spring-security-core.html

⇱ Automatically converting password hashes in Grails spring-security-core


I was looking at this Stack Overflow question about converting password hashes and realized that it’s possible and rather convenient when using the spring-security-core plugin to automate the process.

To start, we’ll need a PasswordEncoder that can work with both algorithms. Here I’m assuming that you’ll be converting from SHA-256 (optionally with a salt) to bcrypt, but the general approach is mostly independent of the algorithms. Sha256ToBCryptPasswordEncoder will always hash new passwords using bcrypt, but can detect the difference between hashes from SHA-256 and bcrypt in isPasswordValid:
 

package com.burtbeckwith.grails.security;

import grails.plugin.springsecurity.authentication.encoding.BCryptPasswordEncoder;

import org.springframework.security.authentication.encoding.MessageDigestPasswordEncoder;

public class Sha256ToBCryptPasswordEncoder
 implements org.springframework.security.authentication.encoding.PasswordEncoder {

 protected MessageDigestPasswordEncoder sha256PasswordEncoder;
 protected BCryptPasswordEncoder bcryptPasswordEncoder;

 public String encodePassword(String rawPass, Object salt) {
 return bcryptPasswordEncoder.encodePassword(rawPass, null);
 }

 public boolean isPasswordValid(String encPass,
 String rawPass, Object salt) {
 if (encPass.startsWith("$2a$10$") && encPass.length() == 60) {
 // already bcrypt
 return bcryptPasswordEncoder.isPasswordValid(
 encPass, rawPass, null);
 }

 if (encPass.length() == 64) {
 return sha256PasswordEncoder.isPasswordValid(
 encPass, rawPass, salt);
 }

 // TODO
 return false;
 }

 /**
 * Dependency injection for the bcrypt password encoder
 * @param encoder the encoder
 */
 public void setBcryptPasswordEncoder(BCryptPasswordEncoder encoder) {
 bcryptPasswordEncoder = encoder;
 }

 /**
 * Dependency injection for the SHA-256 password encoder
 * @param encoder the encoder
 */
 public void setSha256PasswordEncoder(
 MessageDigestPasswordEncoder encoder) {
 sha256PasswordEncoder = encoder;
 }
}

This needs dependency injections for properly configured SHA-256 and bcrypt encoders, and we’ll see that in a bit.

Sha256ToBCryptPasswordEncoder cannot make any changes as only password information is available, so we’ll subclass DaoAuthenticationProvider and do this work in additionalAuthenticationChecks:

package com.burtbeckwith.grails.security

import grails.plugin.springsecurity.SpringSecurityUtils
import grails.plugin.springsecurity.userdetails.GrailsUser

import org.springframework.security.authentication.UsernamePasswordAuthenticationToken
import org.springframework.security.authentication.dao.DaoAuthenticationProvider
import org.springframework.security.core.AuthenticationException
import org.springframework.security.core.userdetails.UserDetails

class PasswordFixingDaoAuthenticationProvider
extends DaoAuthenticationProvider {

 def grailsApplication

 protected void additionalAuthenticationChecks(
 UserDetails userDetails,
 UsernamePasswordAuthenticationToken authentication)
 throws AuthenticationException {
 super.additionalAuthenticationChecks userDetails, authentication

 // if we got this far the password was ok

 String oldHashedPassword = userDetails.getPassword()
 if (oldHashedPassword.startsWith('$2a$10$') &&
 oldHashedPassword.length() == 60) {
 // already bcrypt
 return
 }

 if (oldHashedPassword.length() != 64) {
 // TODO
 return
 }

 String bcryptPassword = getPasswordEncoder().encodePassword(
 authentication.credentials, null) 

 // use HQL to update the password in the database directly

 def conf = SpringSecurityUtils.securityConfig
 String userClassName = conf.userLookup.userDomainClassName
 Class<?> User = grailsApplication.getDomainClass(userClassName).clazz

 def args = [p: bcryptPassword]
 String hql = 'update ' + User.name + ' u set u.password=:p where '
 if (userDetails instanceof GrailsUser) {
 hql += 'u.id=:id'
 args.id = userDetails.id
 }
 else {
 hql += 'u.' + conf.userLookup.usernamePropertyName + '=:un'
 args.un = userDetails.username
 }

 User.withNewSession {
 User.withTransaction {
 User.executeUpdate hql, args
 }
 }
 }
}

Calling super.additionalAuthenticationChecks() will ensure that a password was provided and it will be verified using either SHA-256 or bcrypt by Sha256ToBCryptPasswordEncoder, so if there is no exception thrown it’s safe to update the password. Note that the update code is generic and can be made more compact by hard-coding your class and property names.

We register Sha256ToBCryptPasswordEncoder as the passwordEncoder bean, and create bcryptPasswordEncoder and sha256PasswordEncoder beans, configured with the SHA-256 settings that were being used, and the bcrypt settings that will be used (configure those in Config.groovy as described in the docs). Also configure the bean override of daoAuthenticationProvider to be a PasswordFixingDaoAuthenticationProvider with the same configuration as is done in SpringSecurityCoreGrailsPlugin.groovy with the addition of the grailsApplication reference:

import grails.plugin.springsecurity.SpringSecurityUtils
import grails.plugin.springsecurity.authentication.encoding.BCryptPasswordEncoder

import org.springframework.security.authentication.encoding.MessageDigestPasswordEncoder

import com.burtbeckwith.grails.security.PasswordFixingDaoAuthenticationProvider
import com.burtbeckwith.grails.security.Sha256ToBCryptPasswordEncoder

beans = {

 def conf = SpringSecurityUtils.securityConfig

 bcryptPasswordEncoder(BCryptPasswordEncoder, conf.password.bcrypt.logrounds) // 10

 sha256PasswordEncoder(MessageDigestPasswordEncoder, conf.password.algorithm) {
 encodeHashAsBase64 = conf.password.encodeHashAsBase64 // false
 iterations = conf.password.hash.iterations // 10000
 }

 passwordEncoder(Sha256ToBCryptPasswordEncoder) {
 bcryptPasswordEncoder = ref('bcryptPasswordEncoder')
 sha256PasswordEncoder = ref('sha256PasswordEncoder')
 }

 daoAuthenticationProvider(PasswordFixingDaoAuthenticationProvider) {
 userDetailsService = ref('userDetailsService')
 passwordEncoder = ref('passwordEncoder')
 userCache = ref('userCache')
 saltSource = ref('saltSource')
 preAuthenticationChecks = ref('preAuthenticationChecks')
 postAuthenticationChecks = ref('postAuthenticationChecks')
 authoritiesMapper = ref('authoritiesMapper')
 hideUserNotFoundExceptions = conf.dao.hideUserNotFoundExceptions // true
 grailsApplication = ref('grailsApplication')
 }
}

With this configuration, new users’ passwords will be hashed with bcrypt, and valid existing users’ passwords will be converted to bcrypt using the plaintext passwords used during login. Once your users are converted, back out these changes and convert to the standard bcrypt approach. This would involve deleting the grails.plugin.springsecurity.password.algorithm attribute and all salt configuration since bcrypt doesn’t support a salt, deleting Sha256ToBCryptPasswordEncoder and PasswordFixingDaoAuthenticationProvider, and removing the bcryptPasswordEncoder and sha256PasswordEncoder bean definitions and passwordEncoder and daoAuthenticationProvider overrides from resources.groovy since the beans configured by the plugin using Config.groovy settings will be sufficient. Also if you had added salt to the User class encodePassword method, e.g.

protected void encodePassword() {
 password = springSecurityService.encodePassword(password, username)
}

convert it back to the default without a salt:

protected void encodePassword() {
 password = springSecurityService.encodePassword(password)
}
Do you want to know how to develop your skillset to become a Java Rockstar?
Subscribe to our newsletter to start Rocking right now!
To get you started we give you our best selling eBooks for FREE!
1. JPA Mini Book
2. JVM Troubleshooting Guide
3. JUnit Tutorial for Unit Testing
4. Java Annotations Tutorial
5. Java Interview Questions
6. Spring Interview Questions
7. Android UI Design
and many more ....
I agree to the Terms and Privacy Policy

Thank you!

We will contact you soon.

Tags
Grails
👁 Photo of Burt Beckwith
Burt Beckwith
January 3rd, 2014Last Updated: January 4th, 2014
0 227 3 minutes read
Back to top button
Close
wpDiscuz