Secure JAX-RS resources using annotations
We can secure Java API for RESTful Web Services (JAX-RS) resources using annotations that specify security settings.
This task assumes that we have developed the application and identified the JAX-RS resources to secure using annotations for security.
We can secure JAX-RS resources using annotations for security supported by JSR 250. Use the following annotations to add authorization semantics to the JAX-RS application resources:
- @PermitAll - specifies that all security roles are permitted to access the JAX-RS resources
- @DenyAll - specifies that no security roles are permitted to access the JAX-RS resources
- @RolesAllowed - specifies the security roles that are permitted to access the JAX-RS resources
We 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 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:
- @DenyAll
- @RolesAllowed
- @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 specified at the class level do not affect resources inherited from a superclass.
- Rule for overriding method(s)
- Annotations on resources that correspond to overridden methods in subclasses take precedence over annotations 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
- We cannot have multiple @RolesAllowed annotations simultaneously on a resource. For example, we 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 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 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> </login-config> </web-app>
In the previous sample web.xml file, Role1 is used for the entire application. If we are only defining declarative security annotations and we are not using authorization constraints from the web.xml file, we can map this role for the JAX-RS application to the AllAuthenticated special subject for user authentication.
Tasks
- Determine if there are security constraints defined by the web.xml file for our JAX-RS application.
- Configure the web.xml file to add security constraints. Security constraints configured in the deployment descriptor, the web.xml file, take precedence over security constraints that are programmatically annotated in the application.
- Determine to add annotations for security, in addition to any constraints in the web.xml file. Decide to add one of the @PermitAll, @DenyAll and @RolesAllowed annotations to provide additional security for our JAX-RS resources. Consider the rules for adding annotations for security such as precedence and inheritance described previously.
We have defined secure JAX-RS resources using declarative security annotations.
Example
The following code snippet demonstrates how we 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) { } }
Implement secure JAX-RS applications Administer secure JAX-RS applications