I'm currently trying to integrate JAX-RS with Spring Security for authorization (authorization only; I use a custom authentication mechanism). I found the following resources describing integration between CXF and Spring Security:
- http://www.nabble.com/Re:-CXF%2BACEGI-%2B-Anybody-out-there--p12759358.html (WS-Security) - http://www.emforge.org/wiki/WebServicesImplementation (WS-Security) - There is also a JAX-RS systest (see systest/jaxrs/src/test/resources/jaxrs_security/WEB-INF/beans.xml in the trunk) that integrates Spring Security with JAX-RS. In order for (annotation driven) authorization to work, it is necessary to use SecurityContextHolder to associate the SecurityContext/Authentication with the current thread. In the first two references, this is done in a custom interceptor, while the systest uses a servlet filter (that implements HTTP basic authentication). I see two issues with these approaches: - The service is not necessarily invoked in the same thread as the interceptor or servlet filter (e.g. in-only operations). If that happens, the security context will not be set up correctly. - The code in the first two references never resets the authentication in the SecurityContext (by calling SecurityContextHolder.getContext().setAuthentication(null)). I fear that it is therefore possible that a service may accidentally get the authentication from a previous request. This is only a problem when using an interceptor, but using a servlet filter may not always be possible (e.g. for WS-Security). The approach that I use to avoid these problems is to insert a proxy in front of the Invoker (JAXRSInvoker in my case). This proxy looks as follows: public class SpringSecurityInvokerProxy implements Invoker { private Invoker target; public Invoker getTarget() { return target; } public void setTarget(Invoker target) { this.target = target; } public Object invoke(Exchange exchange, Object o) { Authentication authentication = exchange.get(Authentication.class); SecurityContext securityContext = SecurityContextHolder.getContext(); securityContext.setAuthentication(authentication); try { return target.invoke(exchange, o); } finally { securityContext.setAuthentication(null); } } } The Authentication object is added to the exchange by an interceptor that implements the custom authentication mechanism. The try/finally block here makes sure that the security context is reset right after the invocation of the service. The corresponding configuration is: <jaxrs:server address="/rest"> <jaxrs:serviceBeans> ... </jaxrs:serviceBeans> <jaxrs:providers> ... </jaxrs:providers> <jaxrs:invoker> <bean class="myapp.security.SpringSecurityInvokerProxy"> <property name="target"> <bean class="org.apache.cxf.jaxrs.JAXRSInvoker"/> </property> </bean> </jaxrs:invoker> </jaxrs:server> This works well for me, but I would like to know if there is a better/easier way to achieve this. Regards, Andreas
