Grails Testing Acegi Security

September 1, 2008 - 3 minute read -
mock-objects grails security acegi Unit Testing

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.