You can do this with spring security and the grail without any problems.
I have used the following two methods in the past for similar tasks. Both require the spring ACL plugin, which provides @PreAuthorize and @PostAuthorize .
Custom PermissionEvaluator
You can use the hasPermission() methods in security annotations and create a custom PermissionEvaluator . Inside the code, it looks like this:
@PreAuthorize("hasPermission(#myObject, 'update')") public void updateSomething(myObject) { .. }
The hasPermission() calls hasPermission() routed to the PermissionEvaluator security service on spring. To write your own implementation, you must implement the PermissionEvaluator interface:
class MyPermissionEvaluator implements PermissionEvaluator { @Override public boolean hasPermission(Authentication authentication, Object targetDomainObject, Object permission) {
To register your PermissionEvaluator , you must override the bean named expressionHandler . You do this by adding the following lines to conf/spring/resources.groovy :
beans = { expressionHandler(MyExpressionHandler) { parameterNameDiscoverer = ref('parameterNameDiscoverer') permissionEvaluator = ref('myPermissionEvaluator') // your PermissionEvaluator roleHierarchy = ref('roleHierarchy') trustResolver = ref('authenticationTrustResolver') } myPermissionEvaluator(MyPermissionEvaluator) }
Inside resources.groovy you can define beans, as you would in applicationContext.xml when using spring. The above lines create a bean of type MyPermissionEvaluator named bean MyPermissionEvaluator . spring securities expressionHandler bean is overridden by a bean of type MyExpressionHandler . Other dependencies are copied from the spring ACL plugin configuration file.
Service Calls in Security Annotations
If the design of the hasPermission() methods does not fulfill all your requirements, you can use simple utility calls instead. The annotations @PostAuthorize and @PreAuthorize use SPEL to evaluate the expression. In SPEL, you can use the @ symbol to access beans. For instance:
@PreAuthorize("@securityService.canAccess(#myObject)") public void doSomething(myObject) { .. }
This calls the canAccess bean method called securityService and passes the method argument to it.
To use this approach, you need to register the BeanResolver with an EvaluationContext . To do this, you need to override the DefaultMethodSecurityExpressionHandler , which is configured by the spring ACL plugin.
It might look like this:
class MyExpressionHandler extends DefaultMethodSecurityExpressionHandler { BeanResolver beanResolver @Override public EvaluationContext createEvaluationContext(Authentication auth, MethodInvocation mi) { StandardEvaluationContext ctx = (StandardEvaluationContext) super.createEvaluationContext(auth, mi) ctx.setBeanResolver(beanResolver)
BeanResolver is a simple interface that resolves the bean name to a bean instance:
class GrailsBeanResolver implements BeanResolver { GrailsApplication grailsApplication @Override public Object resolve(EvaluationContext evaluationContext, String beanName) throws AccessException { return grailsApplication.mainContext.getBean(beanName) } }
And finally add beans to resources.groovy :
expressionHandler(MyExpressionHandler) { parameterNameDiscoverer = ref('parameterNameDiscoverer') permissionEvaluator = ref('permissionEvaluator') roleHierarchy = ref('roleHierarchy') trustResolver = ref('authenticationTrustResolver') beanResolver = ref('beanResolver')
Update (2013-10-22): Recently I wrote a blog post stating that this is what gives some additional information.