Last updated by 1 year ago

Page: Simple Dynamic Password Codec, Version:4

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.

Note that this is for demonstration purposes only. Do not roll your own security implementation. Use an established framework, for example the spring-security-core or Shiro plugins.

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

grails-app/utils/PasswordCodec.groovy:

import java.security.MessageDigest
import org.apache.commons.codec.binary.Base64

class PasswordCodec {

static encode = { String s -> MessageDigest md = MessageDigest.getInstance('SHA') md.update s.getBytes('UTF-8') Base64.encodeBase64 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') } }