I have a problem with a Jersey/Spring RESTful web application I'm building. I want to use the @PreAuthorize annotation to secure my endpoints. However, I need to have access to the UriInfo because I do work with the query parameters.
Everything works fine until I secure the method, then suddenly my UriInfo is null. I'm fairly certain this has to do with how @PreAuthorize is causing things to be scoped - no longer at the request level.
@Component
@Path("/equipment")
public class Equipment
{
@Context
UriInfo ui;
@PreAuthorize("hasAnyRole('ROLE_ANALYST', 'ROLE_DEVELOPER')")
@GET
@Produces(MediaType.APPLICATION_JSON)
public def list() {
println ui
return [:]
}
}
The simple class below will print "null".
If you remove the @PreAuthorize annotation, you get the expected result - org.glassfish.jersey.internal.inject.UriInfoInjectee@23b21e3
Based on things I've seen in other questions, let me say in advance my application context already has this line:
<security:global-method-security pre-post-annotations="enabled"/>
and the authorization part is working perfectly. It's just the injection of UriInfo that's failing.
I am using Spring 3.1.4 and Jersey 2.3. Code provided is in Groovy but that's not the problem.
Thank you for your help.
So, I've come up with a solution that gets me around my problem and I'm leaving it here for posterity. The answer doesn't satisfy the "why" of it all, but it does get my application working and it's not really a munge.
Instead of injecting UriInfo at the class level, I inject it at the method level. I got the idea from here. Their explanation is that if a method signature might get modified, inject it there. I guess Spring Security is doing that, but I don't understand why that would break something injected at the class level.
Working code for posterity:
@PreAuthorize("hasAnyRole('ROLE_ANALYST', 'ROLE_DEVELOPER')")
@GET
@Produces(MediaType.APPLICATION_JSON)
public def list(@Context UriInfo ui) {
...
}