Grails Testing Acegi Security

Almost every web application I create needs some form of user authentication and authorization. Grails provides a great plugin system that allows you to extend the base framework to provide these kinds of features. My current favorite security plugin for Grails is the Acegi Security Plugin. It’s built using the Spring Security framework and the robust and widely used Acegi framework. I like the fact that it is built on top of existing, well-known frameworks which is the philosophy of Grails itself. It is also a flexible plugin that has a good default object model.

One of the situations that inevitably arises is how to unit test code that depends on your security framework. Either you will want to test that basic authorization is working, or you might have code that makes decisions based upon who is logged in or what roles they might have. To run those test you have to setup your test cases so that the code that works when the system is running normally is tested.

Unit Testing Setup for Testing Acegi Security Code

This situation arose for me the other day and so I thought I would share the solution that I came up with.


import org.springframework.security.context.SecurityContextHolder as SCH
import org.springframework.security.providers.TestingAuthenticationToken
import org.springframework.security.GrantedAuthority
import org.springframework.security.Authentication
import org.springframework.security.GrantedAuthorityImpl

class AuthenticationBaseTests extends GroovyTestCase {
def setUp() {
def user = User.get(1) // or create a new one if one doesn't exist
authenticate(user, "abc123", [new GrantedAuthorityImpl('ROLE_ADMIN')])
}

protected Authentication authenticate(user, credentials, authorities) {
def principal = new Expando()
principal.domainClass = user

Authentication authentication = new TestingAuthenticationToken(principal, null, authorities as GrantedAuthority[])
authentication.authenticated = true
SCH.context.authentication = authentication
return authentication
}
}

setUp()

The setUp() method will get executed prior to your tests being run. So if you want to do different things for each test you would want to move this code to a more appropriate place. In the setup method we are creating our Principle class, in this case, the User. Next we pass the user along with all of the roles we want the user to have for the given test case.

authenticate(user, credentials, authorities)

The real setup work is done in the authenticate() method. This method does the real work of setting up the Authentication Token and setting it in the static context, which is a thread local variable I think, that is used by the framework to determine who is making the request and what rights they have.

The fun thing about this message is the use of the Expando class. Expando allows you to create a class on the fly. This is a really interesting way to do a Mock object on-the-fly in Groovy. In this case we’re creating a Mock authentication principle. We know, by looking at the Acegi Security code, that the security framework expects an object that will call domainClass to get the underlying implementation of the User (or Principle) implemented in the application. That will return us the User object that we are setting.

This simple method can be added to a base class and then inherited from any tests that need user authentication to run successfully.

6 thoughts on “Grails Testing Acegi Security”

  1. Awesome. This is just what I was looking for. I removed the credential from the method as its not uses anywhere.
    Thank you for posting this. It would be great to have a link or this quick olverview on the acegi plug-in page. I finally found this after searching but only after hacking for a good 2 hours.

  2. Awesome. I changed it a little to use all information in user:


    protected Authentication authenticate(user) {
    def principal = new Expando()
    principal.domainClass = user

    GrantedAuthority[] grantedAuthorities = user.authorities?.toArray()?.collect{new GrantedAuthorityImpl(it.authority)}.toArray()

    Authentication authentication = new TestingAuthenticationToken(principal,user.passwd,grantedAuthorities)

    authentication.authenticated = true
    SCH.context.authentication = authentication
    return authentication
    }

  3. Any idea why TestingAuthenticationToken is not located in providers in version 0.5.2 of this plugin?

    And is there another way to login in an integration test?

  4. TestingAuthenticationToken was removed from spring security core, but is back in the latest version .
    see http://forum.springsource.org/showthread.php?t=61373

    sadly, the version used in grails 1.2.0 is the one without this class

    I used the following code to solve this issue.


    protected Authentication authenticate(User user, String credentials) {

    def authorities = user.authorities.collect { new GrantedAuthorityImpl(it.authority) }

    def userDetails = new GrailsUserImpl(user.username, user.passwd, user.enabled, user.enabled, user.enabled, user.enabled, authorities as GrantedAuthority[], user)

    SCH.context.authentication = new UsernamePasswordAuthenticationToken(userDetails, user.passwd, userDetails.authorities)

    }

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>