Recipe11.9.Letting the Container Manage Security


Recipe 11.9. Letting the Container Manage Security

Problem

You want to let the container manage security for your Struts application instead of you having to write all the Java code to support log in (authentication) and access checks (authorization).

Solution

Use container-managed security, as defined by the Java Servlet Specification.

Discussion

A servlet container or J2EE application server can manage security for web applications. Container-managed security provides three main features:


Authentication

You can specify to the container how users are to be authenticated using a login configuration. You indicate if you want the browser to prompt for the username and password, or if you want to use your own custom login page.


Authorization

You can establish security constraints that allow users with certain roles access to specific URLs of the application. If users attempt to access a page to which they aren't authorized, they will be prompted to login using the login configuration.


Secure transport

You can specify which URLs should be accessed using a secure protocol. In practical terms, you indicate which pages can be accessed with the HTTPS protocol (HTTP over Secure Socket Layer).

You configure container-managed security using special XML elements in your web.xml, as shown in Example 11-16.

Example 11-16. Configuring container-managed security in web.xml
<?xml version="1.0" encoding="ISO-8859-1"?> <!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>     <display-name>Struts Cookbook - Chapter 11 : CMS</display-name>     <!-- Action Servlet Configuration -->     <servlet>         <servlet-name>action</servlet-name>         <servlet-class>org.apache.struts.action.ActionServlet</servlet-class>         <init-param>             <param-name>config</param-name>             <param-value>/WEB-INF/struts-config.xml</param-value>         </init-param>         <load-on-startup>1</load-on-startup>     </servlet>     <!-- Action Servlet Mapping -->     <servlet-mapping>         <servlet-name>action</servlet-name>         <url-pattern>*.do</url-pattern>     </servlet-mapping>     <!-- The Welcome File List -->     <welcome-file-list>         <welcome-file>index.jsp</welcome-file>     </welcome-file-list>     <!-- Container-managed security configuration -->     <security-constraint>             <!-- At least one web-resource collection -->         <web-resource-collection>           <web-resource-name>RegPages</web-resource-name>           <description>Registered user pages</description>           <url-pattern>/reg/*</url-pattern>         </web-resource-collection>         <auth-constraint>             <!-- Zero or more role-names -->              <role-name>jscUser</role-name>         </auth-constraint>     </security-constraint>     <security-constraint>         <web-resource-collection>             <web-resource-name>AdminPages</web-resource-name>             <description>Administrative pages</description>             <url-pattern>/admin/*</url-pattern>         </web-resource-collection>         <auth-constraint>             <role-name>jscAdmin</role-name>         </auth-constraint>         <!-- Switch to HTTPS for the admin pages -->         <user-data-constraint>             <transport-guarantee>CONFIDENTIAL</transport-guarantee>         </user-data-constraint>     </security-constraint>     <login-config>         <auth-method>FORM</auth-method>         <realm-name>StrutsCookbookCh11</realm-name>         <form-login-config>             <form-login-page>/cma_logon.jsp</form-login-page>             <form-error-page>/cma_logon_error.jsp</form-error-page>         </form-login-config>     </login-config>     <security-role>         <description>Registered User</description>         <role-name>jscUser</role-name>     </security-role>     <security-role>         <description>Administrators</description>         <role-name>jscAdmin</role-name>     </security-role> </web-app>

Recipe 11.9.3.1 Authentication and authorization

You use the security-constraint element to apply constraints to one or more web resource collectionsi.e., a set of URLs. URL patterns (see the Sidebar 11-1) identify the URLs that comprise each collection. The auth-constraint element identifies the user roles, specified using role-name elements, which can access a constrained URL. If users attempt to access a constrained URL, they must log in based on settings in the login-config element.

The login-config element indicates the authentication to be performed and where the user information can be found. A web application can have one login configuration. The auth-method nested element indicates the type of authentication and accepts the values detailed in Table 11-1.

Table 11-1. J2EE login configuration types

Authentication method

Description

BASIC

The browser pops up a dialog allowing the user to enter a username and password. The username and password are Base-64 encoded and sent to the server.

FORM

Allows for a custom form to be specified. The form must contain a j_username field for the username and j_password field for the password. The form must submit to j_security_check. The username and password are Base-64 encoded.

DIGEST

Just like BASIC authentication, except that the username and password are encrypted into a message digest value. All browsers may not support this configuration.

CLIENT-CERT

The client is required to provide a digital certificate for authentication. This is the most secure configuration and is the most costly; certificates for production use must be purchased from a Certificate Authority.


The majority of applications employing container-managed security use BASIC or FORM-based authentication. With FORM-based authentication, the form-login-page element specifies an HTML or JSP page that users use to submit their authentication credentials. That page, like the one shown in Example 11-17, must submit to the form action named j_security_check and have form fields named j_username and j_password.

Example 11-17. Form-based authentication login page
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <%@ taglib uri="http://struts.apache.org/tags-bean" prefix="bean" %> <html> <head> <title><bean:message key="logon.cma.title"/></title> </head> <body> <form action="j_security_check">     <table border="0" width="100%">         <tr>             <th align="right">                 <bean:message key="prompt.username"/>:             </th>             <td align="left">                 <input type="text" name="j_username" size="16" maxlength="18">             </td>         </tr>         <tr>             <th align="right">                 <bean:message key="prompt.password"/>:             </th>             <td align="left">                 <input type="password" name="j_password" size="16"                  maxlength="18">             </td>         </tr>         <tr>             <td align="right">                 <input type="submit" value="Submit">             </td>             <td align="left">                 <input type="reset">             </td>         </tr>     </table> </form> </body> </html>

In addition to specifying the login, the login configuration may also specify a security realm. A security realm is essentially the store from which a web application retrieves and verifies user credentials. In addition, a realm provides a mechanism for specifying the roles users may have.

The user data for authentication comes from the security realm. The security realm serves as a reference to container-specific security storage. Realms can be based, for example, on property files, XML files, a relational database, or an LDAP-server. Some containers, such as JBoss, provide a mapping between a realm and a Java Authentication and Authorization Service (JAAS) implementation. The mechanism for associating the logical realm named in the web.xml to the concrete realm varies by container.

If you are experimenting with container-managed security and using Tomcat, you can use Tomcat's UserDatabase realm. In a default configuration, Tomcat supports this realm across all deployed applications. The realm uses usernames, passwords, roles, and role assignments specified in the conf/tomcat-users.xml file. A sample file is shown in Example 11-18.

Example 11-18. Sample Tomcat users file
<?xml version='1.0' encoding='utf-8'?> <tomcat-users>   <role rolename="jscUser"/>   <role rolename="tomcat"/>   <role rolename="role1"/>   <role rolename="manager"/>   <role rolename="jscAdmin"/>   <role rolename="admin"/>   <user username="bsiggelkow" password="crazybill" roles="jscUser,jscAdmin"/>   <user username="tomcat" password="tomcat" roles="tomcat"/>   <user username="role1" password="tomcat" roles="role1"/>   <user username="both" password="tomcat" roles="tomcat,role1"/>   <user username="gpburdell" password="gotech" roles="jscUser"/>   <user username="admin" password="admin" roles="admin,manager"/> </tomcat-users>

When users attempt to access an authorization-constrained URL, they will be challenged to enter authentication credentials. If you are using FORM-based authentication, the form-login-page will be displayed. Once the user has been authenticated, your web application can glean useful user data from the HTTP request. The HttpServletRequest provides three particular methods enabled when using container-managed security: getUserPrincipal( ); getremoteUser( ), which returns user identity information, such as the username; and isUserInRole(), which determines if a user has a specified role. These methods can be used in your Action classes to perform such things as the following:

  • Loading the user's profile and storing it in the session

  • Rendering a specific response or redirect to a certain URL based on the user's role

  • Allowing role-based access to Actions as configured in the struts-config.xml file

  • Hiding or displaying presentation components (links, buttons, menus, etc.) based on a user's role (using the logic:present and logic:notPresent tags)

A drawback to the challenge/response authentication model of container-managed security is that users must attempt access to a constrained URL to log in. This behavior can make it difficult for a user to log in proactively. A common trick to permit proactive logins is to create a link on an unsecured page to an authorization-constrained JSP page. Because the JSP page is secured, the user will be forced to log in. The secured JSP page then redirects back to the original unsecured page using the logic:redirect Struts tag:

<%@ taglib uri="http://struts.apache.org/tags-logic.tld" prefix="logic" %> <logic:redirect page="/index.jsp"/>

Many web applications place the login form on every publicly accessible page, usually near the top of the page on the left or right. With container-managed security, however, this technique can't easily be employed. The container itself can only reference the login form specified in the login-config. This limitation forces the chicanery required to emulate a proactive login.

There is no easy workaround for this problem. If you need this capability, as many applications do, use application-managed security. To get the best of both worlds, consider using the Solution shown in Recipe 11.10.

Recipe 11.9.3.2 Secure transport

Container-managed security allows you to force portions of your applications to run under the Secure Socket Layer (SSL) transport, using HTTP over SSL (HTTPS). The example web.xml file (Example 11-16) configures the AdminPages to effectively run under the HTTPS:

<security-constraint>     <web-resource-collection>         <web-resource-name>AdminPages</web-resource-name>         <description>Administrative pages</description>         <url-pattern>/admin/*</url-pattern>     </web-resource-collection>     <auth-constraint>         <role-name>jscAdmin</role-name>     </auth-constraint>     <!-- Switch to HTTPS for the admin pages -->     <user-data-constraint>         <transport-guarantee>CONFIDENTIAL</transport-guarantee>     </user-data-constraint> </security-constraint>

The TRansport-guarantee element accepts values of NONE, INTEGRAL, and CONFIDENTIAL. Specifying either of the latter two values requires requests to the URLs to use the HTTPS protocol over a secured port (typically port 443 or 8443). The value of NONE indicates no particular transport security is required.

Specifying a transport-guarantee of NONE won't make the container switch from the secured protocol (https) to the unsecured protocol (http). Unless you specify http on a request, the application will continue to use https. If you need to switch protocols, consider using the Solution shown in Recipe 11.11.

Most application servers and servlet containers accept the HTTPS protocol. However, you may need to configure the container.

See Also

Container-managed security is convenient and easy to configure, but it can make your application inflexible to changing security requirements and less portable between application servers. Recipe 11-10 provides a Solution that mitigates these problems.

Enabling a servlet container to support https varies by application server. Tomcat provides a simple how-to for this. For Tomcat 5.0, the relevant documentation can be found at http://jakarta.apache.org/tomcat/tomcat-5.0-doc/ssl-howto.html.

If you need finer-grained control of transport security than can be provided by container-managed security, consider using the Solution shown in Recipe 11.11.



    Jakarta Struts Cookbook
    Jakarta Struts Cookbook
    ISBN: 059600771X
    EAN: 2147483647
    Year: 2005
    Pages: 200

    flylib.com © 2008-2017.
    If you may any questions please contact us: flylib@qtcs.net