Thursday 2 October 2014

How to Secure RESTful Webservice via Annotation in Jersey

In my previous how to secure restful webservice I have showed how to secure a RESTful Webservice by configuring in web.xml.

Now we see how to implement security via annotation.

We can provide authorization for JAX-RS resource using the below annotation.
  • @PermitAll - specifies that all security roles are permitted to access your JAX-RS resources
  • @DenyAll - specifies that no security roles are permitted to access your JAX-RS resources
  • @RolesAllowed - specifies the security roles that are permitted to access your JAX-RS resources
Below are the steps to implement security via annoataion. 

1. Create a Custome ResourcConfig by creating a new class and extend it. In the constructor register RolesAllowedDynamicFeature as shown below.

import javax.ws.rs.ApplicationPath;

import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.server.filter.RolesAllowedDynamicFeature;

@ApplicationPath("/")
public class ApplicationResourceConfig extends ResourceConfig{
  public ApplicationResourceConfig() {
         super(MyResource.class);
         register(RolesAllowedDynamicFeature.class);
     }
}

2. Now add Roles that can access the specific resources in JAX-RS resources. In below MyResource class I have added three method with sub path and Roles corresponding to them.


import javax.annotation.security.PermitAll;
import javax.annotation.security.RolesAllowed;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

/**
 * Root resource (exposed at "myresource" path)
 */
@Path("myresource")
public class MyResource {

 /**
  * This method is allowed for all Roles
  * 
  * @return
  */
 @GET
 @Produces(MediaType.TEXT_PLAIN)
 @Path("/unsecured")
 @PermitAll
 public String getsecured() {
  return " Message For all Roles!";
 }

 /**
  * This method is allowed to only users with Role <b>secured</b>
  * 
  * @return
  */
 @GET
 @Produces(MediaType.TEXT_PLAIN)
 @Path("/secured")
 @RolesAllowed("secured")
 public String getSecured() {
  return "Message for user with Role secured!";
 }

 /**
  * This method is allowed to only users with Role <b>admin</b>
  * 
  * @return
  */
 @GET
 @Produces(MediaType.TEXT_PLAIN)
 @Path("/securedadmin")
 @RolesAllowed("admin")
 public String getSecuredadmin() {
  return "Message for user with Role admin!";
 }
}

3. Configure web.xml

Add Custom ResourceConfig create above in init-param


    <init-param>
            <param-name>javax.ws.rs.Application</param-name>
            <param-value>com.ranvanshi.jersey.basicsecurityannotation.ApplicationResourceConfig</param-value>
    </init-param>

Add security-constraint for the Resources. We have provided security entry for enire resources. User has to in Role admin to access the resources.


 <security-constraint>
  <web-resource-collection>
   <web-resource-name>Secured</web-resource-name>
   <url-pattern>/webapi/*</url-pattern>
  </web-resource-collection>
  <auth-constraint>
   <role-name>admin</role-name>
  </auth-constraint>
 </security-constraint>
 <security-role>
  <role-name>admin</role-name>
 </security-role>
 <login-config>
  <auth-method>BASIC</auth-method>
  <realm-name>Login</realm-name>
 </login-config>

Complete web.xml


<?xml version="1.0" encoding="UTF-8"?>
<!-- This web.xml file is not required when using Servlet 3.0 container, 
 see implementation details http://jersey.java.net/nonav/documentation/latest/jax-rs.html -->
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
 <servlet>
  <servlet-name>Jersey Web Application</servlet-name>
  <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
  <init-param>
   <param-name>jersey.config.server.provider.packages</param-name>
   <param-value>com.ranvanshi.jersey.basicsecurityannotation</param-value>
  </init-param>
  <init-param>
   <param-name>javax.ws.rs.Application</param-name>
   <param-value>com.ranvanshi.jersey.basicsecurityannotation.ApplicationResourceConfig</param-value>
  </init-param>
  <load-on-startup>1</load-on-startup>
 </servlet>
 <servlet-mapping>
  <servlet-name>Jersey Web Application</servlet-name>
  <url-pattern>/webapi/*</url-pattern>
 </servlet-mapping>
 <security-constraint>
  <web-resource-collection>
   <web-resource-name>Secured</web-resource-name>
   <url-pattern>/webapi/*</url-pattern>
  </web-resource-collection>
  <auth-constraint>
   <role-name>admin</role-name>
  </auth-constraint>
 </security-constraint>
 <security-role>
  <role-name>admin</role-name>
 </security-role>
 <login-config>
  <auth-method>BASIC</auth-method>
  <realm-name>Login</realm-name>
 </login-config>
</web-app>


This post explains about implementing security via annotation in  Jersey.

Thanks !

2 comments:

  1. Hello,

    Why do we need to repeat role 'Admin' in web xml ?
    Can we minimize use of web xml to strict minimum and use only annotation ?

    thanks,

    Michael

    ReplyDelete
    Replies
    1. Someone tried to push for the integration of the @ServletSecurity annotation in Jersey for defining security constraints but, unfortunately, it didn't went through (https://java.net/jira/browse/JERSEY-470).

      Delete