+

Search Tips   |   Advanced Search

Secure JAX-RS applications within the web container

We can use the security services available from the web container to secure Representational State Transfer (REST) resources. We can configure security mechanisms that define user authentication, transport security, authorization control, and user to role mappings.

To appropriately define security constraints, it is important that you are familiar with the application and the RESTful resources that it exposes. This knowledge helps you to determine appropriate security roles required by the application as well as the individual resources it exposes.

To illustrate how to secure a REST application, this topic uses a sample REST application called AddressBookApp.

Complete the installation of the application on the application server. For example, after you install the AddressBookApp application, the AddressBookApp deployment descriptor found in the profile_root/config/cells/cellName/applications/applicationName.ear/deployments/applicationName_war/applicationName.war/WEB-INF directory looks like the following example:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app id="WebApp_1255468655347">
 <display-name>Sample REST Web Application</display-name>
  <servlet>
    <servlet-name>AddressBookApp</servlet-name>
    <servlet-class>com.ibm.websphere.jaxrs.server.IBMRestServlet</servlet-class>
    <init-param>
      <param-name>javax.ws.rs.Application</param-name>
      <param-value>com.test.AddressBookApplication</param-value>
</init-param>
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>AddressBookApp</servlet-name>
    <url-pattern>/rest/*</url-pattern>
  </servlet-mapping>
</web-app>
In this example, the servlet mapping indicates the REST resources are served under the /app_root_context/rest directory where app_root_context is what you configured during the installation of the application. The default root context is /.

We must enable security for WebSphere Application Server.

We can use the web container to apply authentication as well as authorization constraints to a REST application running in the application server environment. Authentication is a basic security requirement for business REST resources that require a minimum level of security and might need to further protect resources based on the identity of the caller.

We can configure the following security mechanisms for REST resources:

  1. Ensure that security is enabled for the application server.

    1. Start the WAS console.

      Start the deployment manager, and in our browser, type the address of the WAS Network Deployment server. By default, the console is located at http://your_host.your_domain:9060/ibm/console.

      If security is currently disabled, you are prompted for a user ID. Log in with any user ID. However, if security is currently enabled, you are prompted for both a user ID and a password. Log in with a predefined admin ID and password.

    2. Click Security > Global security.

      Select Enable application security.

      Avoid trouble: We must enable administrative security. We can only have application security enabled when administrative security is enabled. gotcha

  2. Add security constraints.

    Edit the web.xml file for the application, or use an assembly tool to add security constraints to the application. The following code snippet is a security constraint applied to the AddressBookApp Sample application:

    <!-- Security constraint for the sample application -->
      <security-constraint id="SecurityConstraint_1">
        <!-- This defines the REST resource associated with the constraint. -->
        <web-resource-collection id="WebResourceCollection_1">
          <web-resource-name>AddressBookApp</web-resource-name>
          <description>Protection area for Rest resource /addresses </description>
          <url-pattern>/rest/addresses</url-pattern>
          <http-method>GET</http-method>
          <http-method>POST</http-method>
        </web-resource-collection>
    
        <!—This defines an authorization constraint by requiring Role1 for the resource. -->
        <auth-constraint id="AuthConstraint_1">
          <description>Used to guard resources under this url-pattern </description>
          <role-name>Role1</role-name>
        </auth-constraint>
      </security-constraint>

    In this example, there is a web resource located at /root_context/rest/addresses that can respond to an HTTP GET or POST request. A security constraint, AuthConstraint_1, is applied to the web resource. The authorization constraint specifies that role Role1 is required for users to access the resource.

  3. Choose one or more of the following security mechanisms to configure for the REST application.

    • Enable basic HTTP authentication.

      1. Add security constraints by editing the web.xml file as previously described.

      2. Configure the web.xml file to enable basic HTTP authentication.

        Edit the web.xml file for the application and add the following element to specify the use of basic HTTP authentication. By default, the application server security runtime environment uses this method of authentication.

        <!-- This defines a HTTP basic authentication login configuration. -->
         <login-config>
                <auth-method>BASIC</auth-method>
                <realm-name>test realm</realm-name>
         </login-config>
        An HTTP basic authentication method is now defined. Users attempting to access the resource are required to login with credentials.

    • Enable form login.

      1. Add security constraints by editing the web.xml file as previously described.

      2. Edit the web.xml file for the application and add the following element to specify the use of form login:

        <login-config>
              <auth-method>FORM</auth-method>
              <form-login-config>
                 <form-login-page>/logon.jsp</form-login-page>
                 <form-error-page>/logonError.jsp</form-error-page>
              </form-login-config>
        </login-config>
        It is important that you replace the logon.jsp and logonError.jsp web page values with the form login and error processing, respectively. When accessing the application, users are redirected through the logon.jsp web page to authenticate. If there is an authentication failure, users are redirected to the logonError.jsp web page. Example placement of logon.jsp and logonError.jsp pages in the application WAR file:
        META-INF    
              logon.jsp
              logonError.jsp
              WEB-INF/classes/
              WEB-INF/classes/
              WEB-INF/classes/com/
              WEB-INF/classes/com/test/   
              WEB- NF/classes/com/test/AddressBookApplication.class
              WEB-INF/classes/com/test/AddressBookResource.class

        The following code snippet illustrates a sample logon form:

        <html>
        <head>
            <title>Login Page</title>
        </head>
        <h2>Hello, please log in:</h2>
        <br><br>
        <form action="j_security_check" method=post>
            <p><strong>Please Enter Your User Name: </strong>
            <input type="text" name="j_username" size="25">
            <p><p><strong>Please Enter Your Password: </strong>
            <input type="password" size="15" name="j_password">
            <p><p>
            <input type="submit" value="Submit">
            <input type="reset" value="Reset">
        </form>
        </html>

    • Enable SSL for the application.

      1. Add security constraints by editing the web.xml file as previously described.

      2. Edit the web.xml file for the application, and add the following element within the security-constraint element:
        <user-data-constraint id="UserDataConstraint_1">
            <transport-guarantee>CONFIDENTIAL</transport-guarantee>
         </user-data-constraint>
        If we do not want to use SSL, we can either skip this constraint or replace the CONFIDENTIAL value with NONE.

    • Enable authorization control to protect resources using URL patterns.

      1. Add security constraints by editing the web.xml file as previously described.

      2. Edit the web.xml file for the application and add the following element within the security-constraint element. In the following example, Role1 and Role2 specify to protect the REST resources, /rest/addresses and /rest/resources/{i}, respectively:
        <security-constraint id="SecurityConstraint_1">
            <web-resource-collection id="WebResourceCollection_1">
              <web-resource-name>AddressBookApp</web-resource-name>
              <description>Protection area for Rest Servlet</description>
              <url-pattern>/rest/addresses</url-pattern>
              <http-method>GET</http-method>
              <http-method>POST</http-method>
            </web-resource-collection>
            <auth-constraint id="AuthConstraint_1">
                 <description> Role1 for this rest resource </description>
                 <role-name>Role1</role-name>
              </auth-constraint> 
        </security-constraint>
        
        <security-constraint id="SecurityConstraint_2">
            <web-resource-collection id="WebResourceCollection_2">
              <web-resource-name>AddressBookApp</web-resource-name>
              <description>Protection area for Rest Servlet</description>
              <url-pattern>/rest/addresses/*</url-pattern>
              <http-method>GET</http-method>
              <http-method>POST</http-method>
            </web-resource-collection>
            <auth-constraint id="AuthConstraint_2">
                 <description> Role2 for this rest resource </description>
                 <role-name>Role2</role-name>
              </auth-constraint>
        </security-constraint>

        In this example, only users that are members of Role1 are able to access root-context/rest/addresses and only users that are members of Role2 are able to access the resource, root-context/rest/addresses/{i}.

        Avoid trouble: It is important that you prefix the path of the protected resources with the servlet mapping in the security constraints defined. To prevent bypassing any access checks, we can choose to map the servlet to the /* path. This mapping protects all resources under the root context.gotcha

        Make sure to define your roles by inserting the role definition elements within the <web-app> element; for example:

        <security-role id="SecurityRole_1">
            <description>This is Role1</description>
            <role-name>Role1</role-name>
        </security-role> 
        <security-role id="SecurityRole_2">
            <description>This is Role2</description>
            <role-name>Role2</role-name>
        </security-role> 

        The changes made to the deployment descriptor are automatically picked up by the application server runtime environment, and we do not need to restart the application or the server. Other types of changes, such as the mapping URL, require that you restart the application server. IBM recommends that you restart the application to verify the changes take effect.

    • Programmatically using the annotated security context.

      Application developers can use the JAX-RS @SecurityContext annotation to programmatically cascade the security context down to the resource on the server side and enable the definition of security attributes during run time. The following is the functionality provided by the SecurityContext interface:

      public String getAuthenticationScheme()
      public Principal getUserPrincipal()
      public boolean isUserInRole(String role)
      Example SecurityContext interface:
      package com.test;
      
      import javax.ws.rs.GET; 
      import javax.ws.rs.Consumes;
      import javax.ws.rs.POST;
      import javax.ws.rs.Path;
      import javax.ws.rs.PathParam;
      import javax.ws.rs.Produces;
      import javax.ws.rs.ext.*;
      import javax.ws.rs.core.SecurityContext;
      import javax.ws.rs.core.Context;
      
      /**   
       * A sample resource that provides access to an address book. 
       * 
       */
      @Path(value="/addresses")
      public class AddressBookResource {
       
       @Context private SecurityContext securityContext;
          
          private static String[] list = new String[] {
              "Michael", "Ron", "Jane", "Sam"
          };
          
          @GET
          @Produces(value="text/plain")
          public String getList() {
             // retrieve the authentication scheme that was used(e.g. BASIC)
             String authnScheme = securityContext.getAuthenticationScheme());
             // retrieve the name of the Principal that invoked the resource        
             String username = securityContext.getUserPrincipal().getName());
             // check if the current user is in Role1 
              Boolean isUserInRole = securityContext.isUserInRole("Role1");
            
              StringBuffer buffer = new StringBuffer();
              buffer.append("{");
              for (int i = 0; i < list.length; ++i) {
                  if (i != 0) 
                      buffer.append(", ");
                  buffer.append(list[i]);
              }
              buffer.append("}");
              
              return buffer.toString();
          }
      }

    • Use the security client handler to perform basic HTTP authentication

      We can optionally use the security client handler to perform basic HTTP authentication with a secure JAX-RS resource. Example simple programming model to accomplish this task:

      /**
       * This snippet illustrates the use of the JAX-RS SecurityHandler by a * client to perform HTTP basic authentication with a target service.
       */ 
       
       import org.apache.wink.client.ClientConfig;
       import org.apache.wink.client.Resource;
       import org.apache.wink.client.RestClient;
       import org.apache.wink.client.handlers.BasicAuthSecurityHandler;
      
       ClientConfig config = new ClientConfig();
        BasicAuthSecurityHandler secHandler = new    
       BasicAuthSecurityHandler();
      
       // Set the user credential.
       secHandler.setUsername("user1");
       secHandler.setPassword("security");
      
       // Add this security handler to the handlers chain.
       config.handlers(secHandler);
      
       // Create the REST client instance. 
       RestClient client = new RestClient(config);
      
       // Create the resource instance to interact with 
       // substitute for the resource address
       resource =  
        client.resource("http://localhost:8080/path/to/resource");
      
      // Now you are ready to call the resource.
      When using the BasicAuthSecurityHandler class, ensure that you target resources using the https scheme for the URLs, and that the target application is SSL-enabled. It is highly recommended to use SSL connections when sending user credentials. You may explicitly turn off the requirement for SSL in the BasicAuthSecurityHandler class by invoking the setSSLRequired method on the security handler with the false value. By default, this value is true.

        secHandler.setSSLRequired(false);

      Optionally, we can also provide the user credentials on the Java command-line for the client as follows:

        java -Duser=test_user -Dpassword=your_password your_client_program

      We can optionally retrieve the user credentials from a properties files whose location specified on the Java command-line as follows:

        java -Dclientpropsdir=directory_for_your_properties_file your_client_program

      where directory_for_your_properties_file contains the wink.client.props file where the user and password properties are set.


Results

After you define security constraints, access to the REST resources defined in the application is subject to successful user authentication only. Additionally, we have applied role constraints to various resource URL patterns to enable role-based access to those resources.


Example

Example web.xml deployment descriptor for the AddressBookApp Sample application where security constraints have been defined using the previous procedure steps:

<web-app id="WebApp_1255468655347">
    <display-name>Sample REST Web Application</display-name>
    <servlet>
        <servlet-name>AddressBookApp</servlet-name>
        <servlet-class>com.ibm.websphere.jaxrs.server.IBMRestServlet</servlet-class>
        <init-param>
            <param-name>javax.ws.rs.Application</param-name>
            <param-value>com.test.AddressBookApplication</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>AddressBookApp</servlet-name>
        <url-pattern>/rest/*</url-pattern>
    </servlet-mapping>
    <security-constraint id="SecurityConstraint_1">
      <web-resource-collection id="WebResourceCollection_1">
        <web-resource-name>AddressBookApp</web-resource-name>
        <description>Protection area for Rest Servlet</description>
        <url-pattern>/rest/addresses</url-pattern>
        <http-method>GET</http-method>
        <http-method>POST</http-method>
      </web-resource-collection>
      <auth-constraint id="AuthConstraint_1">
         <description>Role1 for this rest servlet</description>
         <role-name>Role1</role-name>
      </auth-constraint> 
      <user-data-constraint id="UserDataConstraint_1">
            <transport-guarantee>CONFIDENTIAL</transport-guarantee>
      </user-data-constraint>
    </security-constraint>
    <security-constraint id="SecurityConstraint_2">
      <web-resource-collection id="WebResourceCollection_2">
        <web-resource-name>AddressBookApp</web-resource-name>
        <description>Protection area for Rest Servlet</description>
        <url-pattern>/rest/addresses/*</url-pattern>
        <http-method>GET</http-method>
        <http-method>POST</http-method>
      </web-resource-collection>
      <auth-constraint id="AuthConstraint_2">
         <description>Role2 for this rest servlet</description>
         <role-name>Role2</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 is Role1</description>
         <role-name>Role1</role-name>
    </security-role> 
    <security-role id="SecurityRole_2">
         <description>This is Role2</description>
         <role-name>Role2</role-name>
    </security-role> 
    <login-config>
      <auth-method>FORM</auth-method>
      <form-login-config>
         <form-login-page>/logon.jsp</form-login-page>
         <form-error-page>/logonError.jsp</form-error-page>
      </form-login-config>
    </login-config>
</web-app>


What to do next

Use the console to administer security for the JAX-RS application.


Subtopics


Related tasks

  • Implement secure JAX-RS applications
  • Administer secure JAX-RS applications