Dec 15th, 2010, 07:26 AM
Custom PreInvocation authorization logic
I am struggling with trying to apply some authorization logic before a method is called. I am using Spring Security 3.0.4 with the annotation-driven approach. I have already implemented some simple pre/post invocation logic using the @PreAuthorize and @PostAuthorize annotations.
However, I am now trying to implement some rules which are very specific to the application I am working on and they cannot be expressed with the Spring EL (at least not as far as I can tell). The code involves scanning the method invocation for parameters of a certain type then calling some existing services to determine whether the user has access to view the object.
I started out by thinking the best way to implement was to write a custom PreInvocationAuthorizationAdviceVoter and then use the ConfigAttributes which are passed into the supports and vote methods to figure out whether the voter should abstain, grant, or deny. Unfortunately I can't figure out how to setup the ConfigAttributes. First, I tried using the @Secured annotation but that appears to be incompatible with @PreAuthorize...if I have both annotations on the same method then the @Secured annotation appears to be ignored. Then, I thought I could declare multiple @PreAuthorize annotations (one for my EL expression, one for my custom attribute)...but no that is not allowed.
In reading the reference guide it seems I could use the ACL module but I don't really want to add all of that to my application. Another possible option is to extend the Spring EL to include some custom expressions that can call out to my custom logic but again this seems more complicated than it needs to be.
What is the best way? Ideally I'd like to use both the build-in Spring EL-based authorization (@PreAuthorize) and add custom voters which are initiated by custom ConfigAttributes.
Dec 15th, 2010, 07:43 AM
Why not just implement a traditional AccessDecisionVoter and add that to the AccessDecisionManager? It has full access to the MethodInvocation. You could, for example, use the @Secured annotation with your own prefixed attribute, similar to the way RoleVoter works. Leave out @PreAuthorize completely.
Dec 15th, 2010, 02:07 PM
Thanks a lot for the reply...it's really great to get timely answers on a forum.
What you are saying does make sense for my current use case. However, maybe I'm thinking about this wrong but I anticipate cases were I want to use an existing built-in expression-based authorization AND a custom authorization.
I know the reference manual specifically states that mixing @PreAuthorize and @Secured is not advisable (although it fails to mention that they are actually mutually exclusive). Is there any other way to use a combination of built-in and custom authorization on the same method?
Dec 15th, 2010, 02:11 PM
I should also mention...the approach I am currently using to apply both built-in and custom authorization on the same method is to define a custom method annotation (for example @MyClassAuthorizer). I have a custom AccessDecisionVoter that looks for this annotation on any intercepted method. If the annotation is present then the voter votes...otherwise it abstains. Obviously I would prefer to key off the supplied ConfigAttributes instead...but they simply aren't passed through when both @PreAuthorize and @Secured are used.
Dec 15th, 2010, 04:03 PM
At the moment you can only have one source of security metadata for a method, so you can't combine different annotations. However, if a method is secured using any approach (i.e. some attributes apply), an invocation will still be controlled by a security interceptor, and you can make use of a custom voter.
In practice you can do anything in a custom access-control engine (called from a voter) that you can in an expression, so if you have custom authorization logic, it makes sense to encapsulate it in a single place.