+

Search Tips   |   Advanced Search

Secure JAX-RS applications within the web container

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 we 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 installing the AddressBookApp application, the AddressBookApp deployment descriptor found in...

...and looks like the following example:

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 we configured during the installation of the application. The default root context is /.

You must enable security for WAS.

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:


Secure JAX-RS applications within the web container

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

    1. Start the WAS administrative console.

      Start the deployment manager, and in your browser, type the address of the WAS ND server. By default, the console is located at...

        http://your_host.your_domain:9060/ibm/console

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

    2. Click...

        Security > Global security > Enable application security

      We must enable administrative security. We can only have application security enabled when administrative security is enabled..

  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 our 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 we replace the logon.jsp and logonError.jsp web page values with your 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. The following example illustrates the placement of logon.jsp and logonError.jsp pages in the application web application archive (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}.

        It is important that you prefix the path of the protected resources with your 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.

        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 we make 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 make sure that our 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)
      
      The following example illustrates the 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

      You can optionally use the security client handler to perform basic HTTP authentication with a secure JAX-RS resource. The following example illustrates the 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 our resource address
       resource =  
        client.resource("http://localhost:8080/path/to/resource");
      
      // Now we are ready to call your resource.
      
      When using the BasicAuthSecurityHandler class, ensure that you target resources using the https scheme for our 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 our client as follows:

      java -Duser=test_user -Dpassword=your_password  your_client_program
      

      You can optionally retrieve the user credentials from a properties files whose location we specify 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.

After we 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

The following example illustrates the 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 administrative console to administer security for our JAX-RS application.


Subtopics


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