I improved this a bit further by creating a feature that adds the invoker proxy:
public class AuthorizationFeature extends AbstractFeature {
@Override
public void initialize(Server server, Bus bus) {
Service service = server.getEndpoint().getService();
service.setInvoker(new
SpringSecurityInvokerProxy(service.getInvoker()));
}
}
Now the configuration looks like this:
<jaxrs:server address="/rest">
<jaxrs:serviceBeans>
...
</jaxrs:serviceBeans>
<jaxrs:providers>
...
</jaxrs:providers>
<jaxrs:features>
<bean class="myapp.security.AuthorizationFeature"/>
</jaxrs:features>
</jaxrs:server>
The advantage is that it works in exactly the same way for all
frontends (I tested this successfully with JAX-RS and the simple
frontend) and that there is no need to figure out how to set up the
target invoker.
Does the code in AuthorizationFeature look good?
I also have a working integration between WSS4J and Spring Security
which plays nicely with
SpringSecurityInvokerProxy/AuthorizationFeature. Here is the
configuration for a simple scenario:
<security:authentication-provider>
<security:user-service>
<security:user name="joe" password="password"
authorities="ROLE_USER,ROLE_ADMIN"/>
<security:user name="bob" password="password" authorities="ROLE_USER"/>
</security:user-service>
</security:authentication-provider>
<simple:server serviceClass="myapp.MyService" address="/myservice">
<simple:serviceBean>
<bean class="myapp.MyServiceImpl"/>
</simple:serviceBean>
<simple:inInterceptors>
<bean class="org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor">
<constructor-arg>
<map>
<entry key="action" value="UsernameToken"/>
<entry key="passwordType" value="PasswordText"/>
<entry key="passwordCallbackRef">
<ssec:server-password-callback-handler
logExceptions="true" nestExceptions="false"/>
</entry>
</map>
</constructor-arg>
</bean>
</simple:inInterceptors>
</simple:server>
ssec:server-password-callback-handler is a Spring handler that creates
a password callback handler that delegates authentication to Spring
Security.
If there is interest, I can contribute the corresponding code.
Andreas
On Wed, Sep 16, 2009 at 10:54, Sergey Beryozkin
<[email protected]> wrote:
>
> Hi Andreas
>
> This does look like a neat solution. I think it's worth documenting what you
> suggested.
> Note that we don't support in-only operations for JAX-RS (just yet), but
> either way, what you've done seems to cover all the variations. In one of
> the system tests I added a custom invoker which extends JAXRSInvoker but
> your approach works well too and is more generic.
>
>> - The service is not necessarily invoked in the same thread as the
>> interceptor
>
> I thought that interceptors and the service were actually invoked on the
> same thread. It is transport threads like Jetty threads won't necessarily
> end up invoking on the service.
>
> Dan, can it be that a thread which invoked a given interceptor won't invoke
> the service endpoint ?
>
> By the way there's also a similar test showing how the spring security can
> be used without using annotations :
>
> systest/jaxrs/src/test/resources/jaxrs_security_no_annotations/WEB-INF/beans.xml
>
> cheers, Sergey
>
>
> Andreas Veithen-2 wrote:
>>
>> 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
>>
>>
>
> --
> View this message in context:
> http://www.nabble.com/CXF-%2B-JAX-RS-%2B-Spring-Security-%28Acegi%29-for-authorization-tp25462665p25468445.html
> Sent from the cxf-user mailing list archive at Nabble.com.
>
>