Network Deployment (Distributed operating systems), v8.0 > Secure applications and their environment > Secure web services > Secure JAX-RS web applications
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.
We must 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 WAS.
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:
- Require that users authenticate to the application using either HTTP basic authentication or form login.
- Configure the application to use an SSL channel for transport when invoking REST resources.
- Define role-based authorization constraints on your REST resource patterns.
- Implement the programmatic use of the annotated SecurityContext object to determine user identity and roles.
Procedure
- Ensure that security is enabled for the application server.
- Start the WAS administrative console.
Start the dmgr, and in your browser, type the address of your WAS ND 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 administrative user ID and password.
- Click Security > Global security.
Select Enable application security. We must enable administrative security. We can only have application security enabled when administrative security is enabled.
- 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> <//publib.boulder.ibm.com/infocenter/wasinfo/v8r0/index.jsp?topic=/ -method>GET <///publib.boulder.ibm.com/infocenter/wasinfo/v8r0/index.jsp?topic=/ -method> <//publib.boulder.ibm.com/infocenter/wasinfo/v8r0/index.jsp?topic=/ -method>POST <///publib.boulder.ibm.com/infocenter/wasinfo/v8r0/index.jsp?topic=/ -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.
- Choose one or more of the following security mechanisms to configure for your REST application.
- Enable basic HTTP authentication.
- Add security constraints by editing the web.xml file as previously described.
- 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.
- Add security constraints by editing the web.xml file as previously described.
- 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 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.classThe 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.
- Add security constraints by editing the web.xml file as previously described.
- 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 you do not want to use SSL, you can either skip this constraint or replace the CONFIDENTIAL value with NONE.
- Enable authorization control to protect resources using URL patterns.
- Add security constraints by editing the web.xml file as previously described.
- 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> <//publib.boulder.ibm.com/infocenter/wasinfo/v8r0/index.jsp?topic=/ -method>GET <///publib.boulder.ibm.com/infocenter/wasinfo/v8r0/index.jsp?topic=/ -method> <//publib.boulder.ibm.com/infocenter/wasinfo/v8r0/index.jsp?topic=/ -method>POST <///publib.boulder.ibm.com/infocenter/wasinfo/v8r0/index.jsp?topic=/ -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> <//publib.boulder.ibm.com/infocenter/wasinfo/v8r0/index.jsp?topic=/ -method>GET <///publib.boulder.ibm.com/infocenter/wasinfo/v8r0/index.jsp?topic=/ -method> <//publib.boulder.ibm.com/infocenter/wasinfo/v8r0/index.jsp?topic=/ -method>POST <///publib.boulder.ibm.com/infocenter/wasinfo/v8r0/index.jsp?topic=/ -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 that you define.
To prevent bypassing any access checks, you 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 you make to the deployment descriptor are automatically picked up by the application server runtime environment, and you 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 your 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 your resource address resource = client.resource("http://localhost:8080/path/to/resource"); // Now you are ready to call your resource.For transitioning users: When using the BasicAuthSecurityHandler class, ensure that you target resources using the https scheme for your 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);trnsOptionally, you can also provide the user credentials on the Java command-line for your client as follows:
java -Duser=test_user -Dpassword=your_password your_client_programYou can optionally retrieve the user credentials from a properties files whose location you specify on the Java command-line as follows:
java -Dclientpropsdir=directory_for_your_properties_file your_client_programwhere 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 that are 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> <//publib.boulder.ibm.com/infocenter/wasinfo/v8r0/index.jsp?topic=/ -method>GET <///publib.boulder.ibm.com/infocenter/wasinfo/v8r0/index.jsp?topic=/ -method> <//publib.boulder.ibm.com/infocenter/wasinfo/v8r0/index.jsp?topic=/ -method>POST <///publib.boulder.ibm.com/infocenter/wasinfo/v8r0/index.jsp?topic=/ -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> <//publib.boulder.ibm.com/infocenter/wasinfo/v8r0/index.jsp?topic=/ -method>GET <///publib.boulder.ibm.com/infocenter/wasinfo/v8r0/index.jsp?topic=/ -method> <//publib.boulder.ibm.com/infocenter/wasinfo/v8r0/index.jsp?topic=/ -method>POST <///publib.boulder.ibm.com/infocenter/wasinfo/v8r0/index.jsp?topic=/ -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 admin console to administer security for your JAX-RS application.
Implement secure JAX-RS applications
Administer secure JAX-RS applications