Updating the Logged in User with Acegi/Spring Security in Grails

Following on from my post on how to log in a user using the Grails Acegi/Spring Security plugin I stumbled into a new use for the same code when I tried to update a user’s own details while logged in. The security plugin caches the user’s domain object so any changes are not seen until the next login (wholly unhelpful when you’re trying to implement account management on a Website!).

Stop Caching the User Domain Object

There are a couple of ways to solve this problem, the brute-force approach is to turn off caching of the domain object  so it’s reloaded on each call. Turning off user caching is simple in the latest version of the Spring Security plugin, just add this line to your SecurityConfig.groovy file:

cacheUsers = false

Refresh the Authentication Token

Of course there is a performance hit associated with turning off caching, so instead it’s much more useful to be able to refresh the domain object only when needed. This can be achieved using the same method as logging in a user when the password is not available, as described in my previous post:

import org.springframework.security.context.SecurityContextHolder
import org.springframework.security.providers.UsernamePasswordAuthenticationToken
import org.codehaus.groovy.grails.plugins.springsecurity.GrailsUserImpl
import org.springframework.security.GrantedAuthority
import org.springframework.security.GrantedAuthorityImpl
...
    private def refreshUserPrincipal(username) {
        def user = User.findByUsername(username)
        GrantedAuthority[] auths = user.authorities.collect {
            new GrantedAuthorityImpl(it.authority)
        }
        def grailsUser = new GrailsUserImpl(
                user.username,
                "",
                true,
                true,
                true,
                true,
                auths,
                user)

        def authToken =  new UsernamePasswordAuthenticationToken(
                grailsUser, '', auths)
        SecurityContextHolder.context.authentication = authToken
    }

So by calling the refreshUserPrincipal method after making updates to the user’s domain object you can maintain the benefits of caching while continuing to use the authenticateService.userDomain object to read up-to-date properties of the user.

Update

Also see my post on AOP where I show how this update method can be extended using aspect oriented programming.

Advertisements

2 thoughts on “Updating the Logged in User with Acegi/Spring Security in Grails

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s