« Eclipse 3.1 | Main | The zen of branching »

2005.02.24

JUnit testing with Acegi Security

Here's a tip if you are trying to do some unit testing with Acegi Security - particularly if you are doing role based authorization of method calls on your manager objects via interception.

Basically, a secure method interceptor will a) need an authentication token to play with, and b) a way to  find out what authorities the user has.  We need to cater for this when running the tests.

Acegi Security conveniently provides a TestingAuthenticationToken for unit testing purposes so we are Ok with the token part. You will now need to provide a suitable authentication provider. Somewhat unsurprisingly, there is a TestingAuthenticationProvider that you can add to your Spring config file to accommodate this.

But here is the problem: we already have this configured for production using a different provider (obviously), so we would have to resort to changing the config files depending on if you are running tests or not. This is too fragile for me, so here is the essence of the tip: leave the configuration file alone and dynamically changes the provider in the setup of the unit test.

Here is some code that I have in my JUnit setUp() method:

        // Grant all roles to noddy.
        TestingAuthenticationToken token = new TestingAuthenticationToken(
                "noddy", "test", new GrantedAuthority[] {
                        new GrantedAuthorityImpl("User"),
                        new GrantedAuthorityImpl("Administrator") });
       
        // Override the regular spring configuration
        ProviderManager providerManager = (ProviderManager) ctx.getBean("authenticationManager");
        List list = new ArrayList();
        list.add(new TestingAuthenticationProvider());
        providerManager.setProviders(list);
       
        // Create and store the Acegi SecureContext into the ContextHolder.
        SecureContextImpl secureContext = new SecureContextImpl();
        secureContext.setAuthentication(token);
        ContextHolder.setContext(secureContext);

So... it sets up an authentication token, then resets the authentication managers' provider list with one that contains the TestingAuthenticationProvider. It then creates the context for the method execution.

The problem with this is it does it for every single test method - that is how JUnit works for better or worse.

Hope it proves useful for you.

Update 2007-01-31: I've updated this to work with Acegi 1.0.3 and Spring 2.0.2.

TrackBack

TrackBack URL for this entry:
http://www.typepad.com/services/trackback/6a00d8341c9edc53ef00d834283b5c53ef

Listed below are links to weblogs that reference JUnit testing with Acegi Security:

Comments

Feed You can follow this conversation by subscribing to the comment feed for this post.

Your listing of the classes is helpful, thanks. A trick that I use to get around having to change configuration files for testing is to use three different classes of configuration files: Mainline, Runtime, and Test. Basically a mainline configuration is always loaded, in conjunction with either a runtime or test configuration. So my test AbstractTestBase class has a config location of {"classpath*:META-INF/applicationContext-*.xml", "classpath*:META-INF/testContext-*.xml"}, and my runtime has a config location of {"classpath*:META-INF/applicationContext-*.xml", "classpath*:META-INF/runtimeContext-*.xml"}. When I need to add components, I always add them to the mainline, unless there is a situation like you name here, which would be split up accordingly.
A useful tip - thanks! One problem - the right hand side of the code snippet is getting truncated (both in Firefox & IE). I managed to pluck the code from the html source anyway :)
Nice tip! Just want to mention that in my version av Acegi, 1.0.3, there has been some renaming: SecureContextImpl --> SecurityContextImpl ContextHolder --> SecurityContextHolder
Thanks a lot! You saved me lots of experimenting! And thank Frode Reinertsen, too :)
As of acegi 0.9.0, ContectHolder is now SecurityContextHolder... Other than that an excellent article and yes, saved me lots of time too... which I burnt reading soem of your other posts ;-)

Verify your Comment

Previewing your Comment

This is only a preview. Your comment has not yet been posted.

Working...
Your comment could not be posted. Error type:
Your comment has been saved. Comments are moderated and will not appear until approved by the author. Post another comment

The letters and numbers you entered did not match the image. Please try again.

As a final step before posting your comment, enter the letters and numbers you see in the image below. This prevents automated programs from posting comments.

Having trouble reading this image? View an alternate.

Working...

Post a comment

Comments are moderated, and will not appear until the author has approved them.