Grails Filters open up a whole new world of opportunity for jumping into the request pipeline to do your own custom processing. I’m really excited about getting Referer tracking real soon now, since I’ve learned the basics of Filters when I implemented Gravl’s very basic security model.

The Grails community is working on some first class plugins for Acegi and JSecurity, but for if your security model is coarse grain (authenticated users can do this, everyone else can’t), it’s easy enough to write a simple custom filter for the task (and a good way to learn filters to boot!).

First we’ll add a SecurityFilters class to the conf directory. Then we’ll get busy declaring our filter logic…

def filters = {

        loginCheck(controller: '*', action: '*') {

            before = {
                      // do our security checks here, before the controller action is invoked...
            }
      }
}

Based on some ideas I picked up from The Bishop (The Grails CMS sample includes users with certain roles can do certain things, but that was overkill for Gravl), I hold the security model in an a hashmap, where I map the controller name to a list of public actions.

def publicStuff = [
    "blog" : ["archive", "homePage", "displayOneEntry"],
    "comment" : ["newComment", "preview", "save"],
    "feed": ["feeds"],
    "pdf": ["show"],
    "image" : ["display"],
    "login" : ["form", "login"]
]

Then it’s a matter of checking whether (1) you have an account object in your session - in which case you’re in, or (2) If you aren’t authenticated, make sure the action you’re invoking is in the public list. If you’re heading for a secured page as an unauthenticated user, I send you off to login. Filters don’t seem to have a logger injected at the moment, so excuse my printlns, but I’m sure they’ll be there soon:

if (!session.account) {
    boolean allowed = false

    println "Checking access to controller [${controllerName}] with action [${actionName}] (${request.forwardURI})"

    if (publicStuff.keySet().find { it == controllerName }) {

        if (publicStuff[controllerName].find { it == actionName }) {
            println "Access ok to public controller [${controllerName}] with action [${actionName}]"
            if (controllerName != 'login') // keep last unsecured page in session for post-login return
                session.returnurl = request.forwardURI
            allowed = true
        } else {
            println "Access privileged action: ${actionName}"
            allowed = false
        }

    } else {
        allowed = false
        println "Access privileged controller: ${controllerName}"

    }

    if (!allowed) {
        session.returnurl = request.forwardURI
        println "Setting return url to " + session.returnurl
        redirect(controller: 'login', action: 'form')
    }

    return allowed
} else {
    println "Found user in session"
    return true
}

And you’re up and running with a basic security model! Still need to implement a basic “remember me” cookie, but the sirens of referer tracking are singing… I can feel a RefererFilters class coming on…

In the meantime, have fun with the lightweight security goodness that filters open up… Can’t wait to see the next generation of plugins that use this stuff!