Securing JAX-RS resources using annotations

You can secure Java™ API for RESTful Web Services (JAX-RS) resources by using annotations that specify security settings.

Before you begin

This task assumes that you have developed the application and identified the JAX-RS resources that you want to secure using annotations for security.

About this task

You can secure JAX-RS resources using annotations for security supported by JSR 250. You can use the following annotations to add authorization semantics to your JAX-RS application resources:
  • @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

You can choose to annotate at the class level or at the method level. The following rules govern the annotations for security:

Method level annotations take precedence over annotations at the class level.
In the following code snippet, the JAX-RS resource that is referenced by the @GET and @Path annotation of /addresses and the corresponding getList() method is not restricted and open for public consumption. However, the resource referenced by the @PUT and @Path annotations of the /addresses and the corresponding updateList() method requires the role of Manager; for example:
@Path(value="/addresses")
        @PermitAll
        public class  AddressBookResource {

          @GET
          @Produces(value="text/plain")
          public String getList() {
          }

          @PUT
          @RolesAllowed(“Manager”)
          to public void updateList(String[] books) {
          }
        }
The annotations for security are mutually exclusive.
This means that each resource is only governed by at most one of the annotations for security. For example, the following example is not valid because both @PermitAll and @RolesAllowed are specified:
       @Path(value="/addresses")
       @PermitAll
       @RolesAllowed(“Employee”)
       public class  AddressBookResource {

      @GET
      @Produces(value="text/plain")
      public String getList() {
      }
    }

In the previous code example, the @RolesAllowed annotation takes precedence and the @PermitAll annotation is ignored. Similarly, if the @RolesAllowed annotation and @DenyAll annotation are both specified, the @DenyAll annotation takes precedence.

Similarly, if the @PermitAll and @DenyAll annotations are both specified at the method or at the class level, the @DenyAll annotation takes precedence as it ensures security by conforming to the safe default principle.

If the @PermitAll, @DenyAll and @RolesAllowed annotations are all present at the method or class level the @DenyAll annotation takes precedence over @RolesAllowed and @PermitAll. The order of precedence of these annotations is the following:
  1. @DenyAll
  2. @RolesAllowed
  3. @PermitAll

Rule for inheritance
JSR 250 annotations that are added at the class level only affect the classes that they annotate and the corresponding methods for subresources. Annotations that are specified at the class level do not affect resources that are inherited from a superclass.
Rule for overriding method(s)
Annotations on resources that correspond to overridden methods in subclasses take precedence over annotations that are included in the parent class. In the following snippet, the LocalAdministrator role is used to access the /addresses/local subresource; for example:
       s@Path(value="/addresses")
       @PermitAll
       public class  AddressBookResource {

          @GET
          @Produces(value="text/plain")
          public String getList() {
          } 

          @PUT
          @RolesAllowed(“Administrator”)
          public void updateList(String books) {
          
          }
        }

        @Path(value="/addresses")
        @PermitAll
        public class  LocalAddressBookResource 
                      extends AddressBookResource {
         
          @PUT
          @RolesAllowed(“LocalAdministrator”)
          @Path(value=”local”)  
          public void updateList(String books){  
          
          }
        }
@RolesAllowed consideration
You cannot have multiple @RolesAllowed annotations simultaneously on a resource. For example, you can achieve:
  @RolesAllowed("role1")
   @RolesAllowed("role2")
    public String foo() {
    }
using the following code snippet:
 @RolesAllowed({"role1", "role2"})
  public String foo() {
   }
Considerations for the use of annotations for security and the configuration of security constraints

Annotations for security follow the declarative security model. Security constraints that are configured in the deployment descriptor, the web.xml file, take precedence over security constraints that are programmatically annotated in the application. It is important for developers of JAX-RS resources to consider a balance across configurable security constraints and annotated security constraints. Annotated constraints are additional to any configured security constraints. The JAX-RS runtime environment checks for annotated constraints after the web container runtime environment has checked for security constraints that are configured in the web.xml file.

Configure authentication constraints in the web.xml file. In the following example web.xml file, the SecurityConstraint_1 security constraint is defined. This constraint is used to require authentication to the application. Additionally, the SecurityConstraint_1 security constraint defines constraints on URL patterns corresponding to JAX-RS resources. When a JAX-RS resource is accessed that corresponds to one of these constraints, authorization checks are performed. Access checks are performed for the declarative security annotations only after the configured constraints are verified.
<web-app id="WebApp_someID">
<servlet>
  <servlet-name>AddressBookAppSample</servlet-name>
  <servlet-class>
       org.apache.wink.server.internal.servlet.RestServlet
  </servlet-class>
        <init-param>
            <param-name>javax.ws.rs.Application</param-name>
            <param-value>jaxrs.sample.AddressBookApplication
            </param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
  </servlet>
    <servlet-mapping>
        <servlet-name>AddressBookApp</servlet-name>
        <url-pattern>/*</url-pattern>
    </servlet-mapping>
    <security-constraint id="SecurityConstraint_1">
      <web-resource-collection id="WebResourceCollection_1">
        <web-resource-name>AddressBookAppSample</web-resource-name>
        <description>Protection area for Rest Servlet</description>
        <url-pattern>/*</url-pattern>
        <http-method>GET</http-method>
        <http-method>POST</http-method>
        <http-method>PUT</http-method> 
      </web-resource-collection>
      <auth-constraint id="AuthConstraint_1">
         <description>Role1 for this rest servlet</description>
         <role-name>Role</role-name>
      </auth-constraint> 
      <user-data-constraint id="UserDataConstraint_1">
            <transport-guarantee>CONFIDENTIAL</transport-guarantee>
      </user-data-constraint>
    </security-constraint>
    <security-role id="SecurityRole_1">
         <description>This Role is used to drive authentication
         </description>
         <role-name>Role1</role-name>
    </security-role>  
    <login-config>
        <auth-method>BASIC</auth-method>
        <realm-name>test realm</realm-name>
    </login-config>
</web-app>

In the previous sample web.xml file, Role1 is used for the entire application. If you are only defining declarative security annotations and you are not using authorization constraints from the web.xml file, you can map this role for the JAX-RS application to the AllAuthenticated special subject for user authentication.

Procedure

  1. Determine if there are security constraints defined by the web.xml file for your JAX-RS application.
  2. Configure the web.xml file to add security constraints.
    Security constraints that are configured in the deployment descriptor, the web.xml file, take precedence over security constraints that are programmatically annotated in the application.
  3. Determine if you want to add annotations for security, in addition to any constraints in the web.xml file.
    Decide if you want to add one of the @PermitAll, @DenyAll and @RolesAllowed annotations to provide additional security for your JAX-RS resources. Consider the rules for adding annotations for security such as precedence and inheritance described previously.

Results

You have defined secure JAX-RS resources using declarative security annotations.

Example

The following code snippet demonstrates how you can use security annotations to protect JAX-RS resources. In this example, the /addresses root resource is associated with a @PermitAll annotation and therefore the subresource that corresponds to the @GET and @Produces(value="text/plain") methods is permitted to all users because this resource does not introduce security annotations of its own. However, the subresource that corresponds to the @PUT method is associated with its own @RolesAllowed annotation and requires the Administrator role.
@Path(value="/addresses")
 @PermitAll
 public class  AddressBookResource {

   @GET
   @Produces(value="text/plain")
       public String getList() {
       } 

       
       @RolesAllowed(“Administrator”)
       @PUT
       public void updateList(String books) {
          
       }
    }