Archive for January 12th, 2009

Grails Acegi (Spring Security) Plugin v0.5 Released

Monday, January 12th, 2009

Version 0.5 went out yesterday. This was an interesting one to work on. There were a few relatively minor bug fixes, but there are four new features/enhancements and the plugin now works with Grails 1.1.

Probably the coolest new feature is being able to define security rules directly in the Controllers. Previously there were two ways to define the URL->Role mappings, in a static string (the standard Spring Security approach) or using Requestmap entries in the database. Now there’s a third – using annotations in controllers.

I’d written about using annotations previously and I used that approach. Annotations can be ugly, but I think here they’re great here since they’ll only ever have a fairly short list of values (roles plus special tokens like IS_AUTHENTICATED_FULLY, etc.). You can annotate individual actions and/or put an annotation at the class level and then all of the actions in the controller share those mappings, and if needed you can override that for individual actions. And they’re inheritable, so if you use controller base classes you can define them there and share rules throughout the hierarchy. For example, if you have an AbstractAdminController that all administrative controllers extend you could annotate just the base class with @Secured(['ROLE_ADMIN']) and restrict access to the entire admin hierarchy.

There are some notes here describing the new approach and the original two.

To better support stuff like administrative sections of a site, I added in an IP address filter so you can specify IP ranges (using Ant patterns or masks) for URLs. This way you can restrict access for your admin area to ’10.**’ or ‘192.168.**’ in addition to requiring specific roles to ensure that only users in the intranet or VPN have access.

I also added in support for ChannelProcessingFilter to allow defining which URLs require HTTPS and which require HTTP. With this addition there aren’t many Spring Security filters left that haven’t been mapped in the plugin – just ConcurrentSessionFilter, SessionFixationProtectionFilter, X509PreAuthenticatedProcessingFilter, and RequestHeaderPreAuthenticatedProcessingFilter.

Someone on the Grails user mailing list was talking about Facebook logins, and I’d been wanting an excuse to play with their API so I wired up support for that. It’s of limited use (like the OpenID support) since you don’t get much information from the authentication, so there would be a lot of manual work required in the app when setting up user information in the database. For example, you don’t even get the login name/email, only the numeric ID, so that has to be the username attribute in the User table.

Getting things going with Grails 1.1 was interesting. There was one real bug that I’d introduced in AuthenticatedVetoableDecisionManager – I think it’s a Groovy bug but I worked around it. I had named both a variable and a method deny, and it was trying to invoke deny() on the variable instead of the method. I changed it to denyCount which is more self-documenting and it was fine.

The plugin generates its own controllers and CRUD pages, so I needed to update those to use new 1.1 features. The allowedMethods map is now static so I changed those to avoid warnings at startup. Optimistic locking is now checked in controllers by adding an <input type='hidden'> form element in the GSP with the current domain instance version and checking it against the database after submitting updates, so I wired that up so the User/Role/Requestmap management pages work like non-plugin pages.

I also had to rework my automated testing due to the changes in the way plugins are installed in 1.1. I have an Ant task that creates a test project, installs the plugin, and configures the app for testing. Then I run a suite of automated tests using the WebTest plugin. Plugins are now global by default, so installing a plugin for a second app will share the plugin that the first app installed, which will save a bunch of space both locally and in source control. But I need the plugin to be local to the test app, and this is possible by overriding the default behavior and reverting to the 1.0 approach by setting grails.plugins.dir='plugins' in grails-app/conf/BuildConfig.groovy. And this doesn’t affect 1.0 since BuildConfig.groovy is ignored.

So check out the new release. There are no backwards compatibility issues, so upgrading is simple. Check out the fixes and enhancements here and the docs here.

Creative Commons License
This work is licensed under a Creative Commons Attribution 3.0 License.