Reputation: 31
My question is
"Can I use @RolesAllowed on RESTful Resources implemented on CXF ?".
First of all, I explain the context causing this question.
I'm working at some projects in which developers have to remake one part of the some web systems into RESTful
WEB Apis.This present system has server system built by Spring
and Hibernate
. And its client application as UI is developed by ActionScript
through
FLEX framework
.
Now I'm surveying the proper way to design and remake our present system into RESTful APIs
through reading some documents or develop some prototypes.So, we temporarily decided to use Apache-CXF ver.2.7.4
as JAX-RS
implementation and TOMCAT ver.7
as Web applications container.
Then, I am struggling for the way of user authorizations now.
As you know, I mean the word 'Authorization'
as some control mechanism that constrain some users to access functions according to user's roll like ROLE_ADMIN
, ROLL_EMPLOYEE
and so on.And our team wants to use @RolesAllowed
annotation to constrain user to access some RESTful methods in REST
resource classes.
Through surveying, I knew that we can use @RolesAllowed
annotation if we use Jersey
as JAX-RS
imple and TOMCAT, because Jersey framework provides
com.sun.jersey.api.container.filter.RolesAllowedResourceFilterFactory
for developers to activate @RolesAllowed annotation by adding following lines in web.xml
<init-param>
<param-name>com.sun.jersey.spi.container.ResourceFilters</param-name>
<param-value>
com.sun.jersey.api.container.filter.RolesAllowedResourceFilterFactory
</param-value>
</init-param>
as init-param of jersey's ServletContainer.
But our team has decided Apache CXF
as JAX-RS imple.I've already surveyed the security and authorization parts of web documents in CXF site. But I couldn’t get solutions or how to use @RolesAllowed
on RESTful resource methods.
So If you know the requirements or how to use @RolesAllowed
on RESTful resource implemented on Apache CXF
and TOMCAT
, teach me that, please.Or if you can definitively conclude that we can't use @RolesAllowed
in frameworks choice of Apache CXF
and TOMCAT
, please teach me the background knowledge of that conclusion.
Additionally, I suppose that I can use @RolesAllowed
in REST resource by CXF
on JBOSS
as app server, not on TOMCAT
. Is this assumption true ? I'm sorry that I've not made a trial to use JBOSS
instead of TOMCAT.
Best regards.
Upvotes: 2
Views: 8738
Reputation: 1102
Yes, this can be done. I'll assume that you (like me) did not want to use Spring Security as part of the solution (to handle authentication and authorization) since there seems to be plenty of resources on how to enable the JSR-250 annotations with Spring Security.
My solution began with a simple JAX-RS project built from the CXF-supplied Archetype Project org.apache.cxf.archetype:cxf-jaxrs-service:2.7.5
(lastest GAV @ time of writing).
This gives you a basic HelloWorld
class with supporting config files.
A few modifications need to be made.
First, add the following dependencies to the pom.xml
:
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>jsr250-api</artifactId>
<version>1.0</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.0.1</version>
<scope>provided</scope>
</dependency>
Why? Because Tomcat is not a full J2EE Container, it does not support all JSR-250 Annotations (of which @RolesAllowed
is one). Further, although CXF recognizes and will work with @RolesAllowed
, it does not bundle an implementation, expecting it to be provided by either a J2EE container or the inclusion of the api as above.
The servlet-api
is listed because I needed it at compile time for a method I add to HellowWorld.java
(see below).
Second, modify beans.xml
as follows:
<bean class="my.pkg.HelloWorld" id="helloWorldService"/>
<jaxrs:serviceBeans>
<ref bean="helloWorldService"/>
</jaxrs:serviceBeans>
<bean id="authorizationInterceptor"
class="org.apache.cxf.interceptor.security.SecureAnnotationsInterceptor">
<property name="securedObject" ref="helloWorldService" />
</bean>
The SecureAnnotationsInterceptor
is what will scan the helloWorldService
and enforce the @RolesAllowed
annotations.
Note that the helloWorldService
had to be pulled out of the <jaxrs:serviceBeans>
stanza so it could be referenced both there and in the authorizationInterceptor
.
Third, add some roles and users to tomcat-users.xml
or alternative (e.g. JDBC Realm, etc.) I did this:
<role rolename="hello-user" />
<role rolename="hello-role1"/>
<role rolename="hello-role2" />
<user username="hello1" password="Password1" roles="hello-role1,hello-user"/>
<user username="hello2" password="Password1" roles="hello-role2,hello-user"/>
This creates 2 users who each have a shared role (hello-user
) plus their own distinct role.
Fourth, add the following to web.xml
to enable BASIC
authentication:
<security-constraint>
<web-resource-collection>
<web-resource-name>Hello Services</web-resource-name>
<url-pattern>/hello/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>hello-user</role-name>
</auth-constraint>
</security-constraint>
<login-config>
<auth-method>BASIC</auth-method>
<realm-name>default</realm-name>
</login-config>
With this, I decided to require the role hello-user
for everything under /hello/*
. That's not essential, but beware that I did have some issues omitting some of the stanzas, wildcards and roles... so experiment with care here.
Fifthly (and finally), mark up the HelloWorld.java
class:
@Path("/hello")
@RolesAllowed("hello-user")
public class HelloWorld {
@GET
@Path("/echo/{input}")
@Produces("text/plain")
@RolesAllowed("hello-role1")
public String ping(@PathParam("input") String input) {
return input;
}
@POST
@Produces("application/json")
@Consumes("application/json")
@Path("/jsonBean")
@RolesAllowed("hello-role2")
public Response modifyJson(JsonBean input) {
input.setVal2(input.getVal1());
return Response.ok().entity(input).build();
}
@GET
@Produces("text/plain")
@Path("/cliche")
public Response getClichedMessage(@Context HttpServletRequest request) {
return Response.
ok().
entity("Sending \"Hello World\" to user \"" + request.getUserPrincipal().getName() + "\"").
build();
}
}
I added the last method (getClichedMessage()
) to show that both users can access the method because they have the hello-user
role with which the class is annotated. The SecureAnnotationsInterceptor
is smart enough to handle that.
That's all. Seems to me, this is the STTCPW using just Tomcat, CXF and BASIC authentication. The key for the CXF + @RolesAllowed
is the SecureAnnotationsInterceptor
.
Update: I should acknowledge that Converting Jersey REST Examples to Apache CXF was particularly helpful, especially for pointing out the SecureAnnotationsInterceptor whose connection to @RolesAllowed
is not well documented elsewhere.
Update 2: The Jersey-CXF blog entry doesn't seem be migrated to gmazza
's new blog. However, the example I used is on github. It contains a config file with SecureAnnotationsInterceptor
definition and a bean with @RolesAllowed
annotation
Upvotes: 4