Combining @Context and @RolesAllowed in a JAX-RS resource?

Can I use Context annotation and RolesAllowed on a JAX-RS resource with Apache CXF 2.4.6 and Spring Security 3.2.8?

My CXF configuration:

<jaxrs:server address="/example"> <jaxrs:serviceBeans> <ref bean="myResourceImpl"/> </jaxrs:serviceBeans> </jaxrs:server> 

My java source code:

 @Path("/myresource") public interface MyResource { @GET @Produces(MediaType.TEXT_XML) String get(); } @Named public class MyResourceImpl implements MyResource { @Context private SecurityContext securityContext; @Override @RolesAllowed("ROLE_user") public String get() { return securityContext.getUserPrincipal().getName(); } } 

After starting the server, I get the following exception:

 Caused by: java.lang.IllegalArgumentException: Can not set javax.ws.rs.core.SecurityContext field MyResourceImpl.securityContext to com.sun.proxy.$Proxy473 at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:164) at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:168) at sun.reflect.UnsafeFieldAccessorImpl.ensureObj(UnsafeFieldAccessorImpl.java:55) at sun.reflect.UnsafeObjectFieldAccessorImpl.set(UnsafeObjectFieldAccessorImpl.java:75) at java.lang.reflect.Field.set(Field.java:741) at org.apache.cxf.jaxrs.utils.InjectionUtils$1.run(InjectionUtils.java:164) at java.security.AccessController.doPrivileged(Native Method) at org.apache.cxf.jaxrs.utils.InjectionUtils.injectFieldValue(InjectionUtils.java:160) at org.apache.cxf.jaxrs.utils.InjectionUtils.injectContextProxiesAndApplication(InjectionUtils.java:912) at org.apache.cxf.jaxrs.JAXRSServerFactoryBean.injectContexts(JAXRSServerFactoryBean.java:354) at org.apache.cxf.jaxrs.JAXRSServerFactoryBean.updateClassResourceProviders(JAXRSServerFactoryBean.java:380) at org.apache.cxf.jaxrs.JAXRSServerFactoryBean.create(JAXRSServerFactoryBean.java:145) ... 59 more 

If I delete one of the two annotations, it works fine.

The problem is that Spring creates proxies , and Apache CXF cannot inject this proxy with SecurityContext .

I have to use Spring Security and cannot use container based security .

+2
source share
2 answers

I found four workarounds:

  • Advanced interface

     @Path("/myresource") public interface MyResource { @Context public void setSecurityContext(Security securityContext); @GET @Produces(MediaType.TEXT_XML) String get(); } @Named public class MyResourceImpl implements MyResource { private SecurityContext securityContext; @Override public void setSecurityContext(Security securityContext) { this.securityContext = securityContext } @Override @RolesAllowed("ROLE_user") public String get() { return securityContext.getUserPrincipal().getName(); } } 

    But this solution is not ideal, because my client should not see implementation details.

  • Dedicated Interface

    If I add a second public installer interface for SecurityContext , Apache CXF can insert the JDK proxy using SecurityContext .

     public interface ContextAware { @Context public void setSecurityContext(Security securityContext); } @Path("/myresource") public interface MyResource { @GET @Produces(MediaType.TEXT_XML) String get(); } @Named public class MyResourceImpl implements MyResource, ContextAware { private SecurityContext securityContext; @Override public void setSecurityContext(Security securityContext) { this.securityContext = securityContext } @Override @RolesAllowed("ROLE_user") public String get() { return securityContext.getUserPrincipal().getName(); } } 
  • CGLIB proxy without interface

    If I remove the interface, Spring uses the CGLIB proxy.

     @Named @Path("/myresource") public class MyResourceImpl { @Context private SecurityContext securityContext; @RolesAllowed("ROLE_superadmin") @GET @Produces(MediaType.TEXT_XML) public String get() { return securityContext.getUserPrincipal().getName(); } } 

    But this solution is not very good, because my client should not see implementation details. And my client doesn’t need implementation dependencies.

  • CGLIB proxy with interface

     @Path("/myresource") public interface MyResource { @GET @Produces(MediaType.TEXT_XML) String get(); } @Named public class MyResourceImpl implements MyResource { @Context private SecurityContext securityContext; @Override @RolesAllowed("ROLE_user") public String get() { return securityContext.getUserPrincipal().getName(); } } 
+2
source

I took a small solution from @dur. Instead of using @Context as a field, I passed it as a parameter to my method, which needed it (I used SearchContext ):

 @Path("/myresource") public interface MyResource { @GET @Produces(MediaType.TEXT_XML) String get(@Context SecurityContext securityContext); } @Named public class MyResourceImpl implements MyResource { @Override @RolesAllowed("ROLE_user") public String get(SecurityContext securityContext) { return securityContext.getUserPrincipal().getName(); } } 
0
source

All Articles