I have no special talent. I'm only passionately curious - Albert Einstein
Grails Integration Testing with the new Spring Security Core Plugin Comment on Grails Integration Testing with the new Spring Security Core Plugin 0

If you're not new to Grails, you'll understand that the system and it's plugins have been changing at a whirlwind pace.  I had written a previous article on how to get the Acegi Security plugin for Grails to work correctly.  Recently though, the Acegi Security plugin page advises that we use the Spring Security Core plugin instead.  So, I started using that plugin, and I wanted to find a way to write integration tests on services that rely on an authenticated user being present in the Spring SecurityContextHolder.  This article will outline two concepts; the first is adding createdBy and lastUpdatedBy user auditing to domain classes.  The second concept is how to test these services in integration or unit tests with the dependancy on an "logged in" or authenticated user.

My setup is fairly simple.  First, I have a BaseAuditableEntity class which is a domain class that other domain classes would extend in order to be used in Auditing:

import java.util.Date
class AuditableBaseEntity {
    Date dateCreated = new Date()
    Date lastUpdated = new Date()
    User createdBy
    User lastUpdatedBy   
    static constraints = {
        dateCreated nullable:false
        lastUpdated nullable:false
        createdBy nullable:false
        lastUpdatedBy nullable:false
    }   
    static mapping = {
        sort dateCreated:'asc'
    }
}

Next, I have a BaseAuditableEntityService class which is responsible for obtaining the current principal from the springSecurityService, using the principal to obtain the User object that are used to set on the createdBy and lastUpdatedBy fields on any AuditableBaseEntity class:

class BaseAuditableService {
    def springSecurityService   
    def save(auditable){
        def user = User.get(springSecurityService.principal.id)       
        if(auditable instanceof AuditableBaseEntity){
            if(auditable.createdBy == null){
                auditable.createdBy = user               
            }           
            auditable.lastUpdatedBy = user           
        }       
        return auditable.save()
    }   
}

----------------------------------------------------------------------------

Update August 4th 2010 6:04PM CDT:

It's much easier to test using the SpringSecurityUtils.doWithAuth(username, closure) method like this:

import org.codehaus.groovy.grails.plugins.springsecurity.SpringSecurityUtils

...

void testSaveWithDoWithAuth(){
        SpringSecurityUtils.doWithAuth(testUsername, {
            def blogEntry = new BlogEntry(content:'test content')
            assertNotNull blogEntryService.save(blogEntry)
            assertNotNull blogEntry.createdBy
            assertEquals testUsername, blogEntry.createdBy.username
            assertNotNull blogEntry.lastUpdatedBy
            assertEquals testUsername, blogEntry.lastUpdatedBy.username
            assertNotNull blogEntry.dateCreated
            assertNotNull blogEntry.lastUpdated
        })
    }

You don't need to use the method I described below, but I still feel the example below contains useful information for other purposes.

----------------------------------------------------------------------------

Then I create a GrailsUnitTestCase class, with the following two fields:

    def baseAuditableService
    def daoAuthenticationProvider

The daoAuthenticationProvider class is provided by the Spring Security Core plugin.  Next, lets create the test method for save:

void testSave() {
        def auth = new UsernamePasswordAuthenticationToken('testusername', 'testpassword')
        def authtoken = daoAuthenticationProvider.authenticate(auth)
        SecurityContextHolder.getContext().setAuthentication(authtoken)
        def blogEntry = new BlogEntry(content:'test content')
        blogEntryService.save(blogEntry)
        assertNotNull blogEntry.createdBy
        assertNotNull blogEntry.lastUpdatedBy
        assertNotNull blogEntry.dateCreated
        assertNotNull blogEntry.lastUpdated
    }

You'll notice two classes being introduced here.  The first is the org.springframework.security.authentication.UsernamePasswordAuthenticationToken, which we need to use to instantiate the authentication object in order to 'login' to the system (login is performed by calling "daoAuthenticationProvider.authenticate(auth)").  Next is the org.springframework.security.core.context.SecurityContextHolder class, which we use to set the authentication token.  This will allow you to mock out the existance of an authenticated user session for use in unit and integration tests.

The Spring Security Core plugin class does contain a utility class called SpringSecurityUtils, with a utility method doWithAuth(username, closure), but I am yet to investigate if this works or not.

Resources:


0 comments

Comments are currently disabled

About

David Malone is a Java developer residing in the Twin Cities area.  He has been developing enterprise applications since 2004.  This is his personal blog, as well as his design and development workspace.