Last updated by 1 year ago

Page: Simple Dynamic Password Codec, Version:3

Grails grants you the ability to quickly define dynamic codecs that you can easily call from within your Grails app. One of the most common uses of a such codecs in web applications is the creation of one-way hashed password strings. Grails makes this very easy to implement and use.

First, create a new codec in /grails-app/utils.

grails-app/utils/PasswordCodec.groovy:

import java.security.MessageDigest
import sun.misc.BASE64Encoder
import sun.misc.CharacterEncoder

class PasswordCodec {

static encode = { str -> MessageDigest md = MessageDigest.getInstance('SHA') md.update(str.getBytes('UTF-8')) return new BASE64Encoder().encode(md.digest()) } }

You only need to define the encode closure (codecs may also have a decode closure, but you don't need one for a one-way hash). The above encode closure accepts a string parameter (str). It then creates a SHA-1 MessageDigest to digest the string. The digested string (an array of bytes) is handed off to a Base64Encoder to turn it into the returned encoded hashed string.

You may now call this codec on any string in your grails appplication by calling {{someString.encodeAsPassword()}}. Here is a complete user controller (modified from the one in _Grails - The Definitive Guide_, pgs. 159-167) that uses the PasswordCodec to encode the password when the user registers and to compare an entered password with a stored password when the user logs in.

grails-app/controllers/UserController.groovy:

class UserController {

def login = { if (session.user) { redirect(controller:'topic', action:'list') } }

def handleLogin = { def user = User.findByEmail(params.email) if (!user) { flash.message = "User not found for email ${params.email}" redirect(action:'login') return }

if (user.password != params.password.encodeAsPassword()) { flash.message = "Incorrect password for ${params.email}" redirect(action:'login') return }

session.user = user redirect(controller:'topic', action:'list') }

def register = {}

def handleRegistration = { def user = new User(params) if (params.password != params.confirm) { flash.message = "The passwords you entered do not match." redirect(action:'register') return }

user.password = params.password.encodeAsPassword() if (!user.save()) { flash.user = user redirect(action:'register') return }

redirect(controller:'topic', action:'list') } }