4.8 Programmatic Security

 <  Day Day Up  >  

Declarative security facilities in the Java Servlet specification define the primary mechanisms by which the Web container manages and enforces security. However, in some scenarios, these policies are insufficient to handle the security requirements of an enterprise. In these cases, applications themselves must include security code. APIs are available to address these scenarios. This section describes these APIs and the scenarios in which they are likely to be useful.

4.8.1 Principal Information

Many Web applications want to get information about the user making the request. This information is used for various reasons. For example, it may be important to provide personalized presentation based on the user's profile and achieve fine-grained control of information access and presentation. To faciliate these scenarios, the Java Servlet specification provides access to the user name through the getUserPrincipal() method available in the HttpServletRequest object. This method returns a java.security.Principal object that represents the user who submitted the servlet request. The getName() method on the Principal object is of particular interest for Web applications, as it returns the name of the calling user. Unfortunately, the format of the user name returned is dependent on the J2EE product implementation, so the java.lang.String value that getName() returns is not likely to be consistent across J2EE implementations . For example, if the end user logs onto the Fabrikam456 travel agency Web site as bob , the getName() method may return bob , bob@fabrikam456 , and so on.

In our travel agency scenario, a reservation portal can use the user name to present the information in a personalized fashion. In that environment, the user information can also be used to retrieve the user's profile and display user-specific information. For example, when customer Bob Smith flying out of the Raleigh-Durham (RDU) airport visits the travel agency Web site and logs on, he may be presented with the latest air fares out of the RDU airport, weather information at RDU, and information about his frequent destination(s). This result can be achieved by finding out the name of the user via the getUserPrincipal() and getName() APIs and then using that information to retrieve the user's profile.

In Web applications that are developed in non-Java environments, principal information is typically obtained through CGI variables that the Web server makes available. In particular, to obtain the name of the requesting user, CGI programmers can access the REMOTE_USER variable. In the Java Servlet specification, the information equivalent to the REMOTE_USER CGI variable is made available through a getRemoteUser() method call on an HttpServletRequest object. This method returns a String , which is likely, though not guaranteed , to be identical to the String obtained by calling getName() on the Principal object returned by getUserPrincipal() .

Listing 4.14 shows a JSP application, Home, invoking getRemoteUser() on an HttpServbletRequest object to obtain the name of the user making the request.

Listing 4.14. Home.jsp
 <HTML>    <HEAD>       <TITLE>Fabrikam456 Online</TITLE>    </HEAD>    <BODY>       <H1>Hi <%=(request.getRemoteUser() != null? ", " +       request.getRemoteUser() : "")%>, welcome to       Fabrikam456!</H1>       <!-- the rest of the JSP code goes here ... --!>    </BODY> </HTML> 

Figure 4.10 shows a scenario involving the Home application. In this scenario, user Bob Smith logs on to the Fabrikam456 Web site and is presented personalized Web contents, such as his recent travels , destinations of interest, weather information at his frequent destinations, and promotions he is entitled to by virtue of his mileage.

Figure 4.10. Personalized Contents Based on Principal Information

graphics/04fig10.gif

4.8.2 Authorization Information

It is common practice for an application's user interface to be based on the user's security authority. For example, for usability reasons, it is considered important to present links to only the information that the requester can access. Presenting contents based on the entitlements of a user is sometimes known as proactive authorization ”the ability to find out whether a user can access a resource even before presenting a way to access it (see Section 3.10.2 on page 94). Alternatively, in a reactive authorization mode, users have to try accessing a resource to determine whether they are authorized for it. Proactive authorization is clearly useful in many enterprise scenarios, including administration, showing only the resources a user can administer; e-business transactions, making only the offers for which the a user is eligible; and enterprise information management, providing only those pieces of budget information the user is entitled to access and manage.

Consider a scenario in which the company Fabrikam456 wants to provide only its platinum -level customers with special offers (see Figure 4.10). This can be accomplished based on whether the customer belongs to a particular user group , which implies that the application needs to have knowledge of the deployment environment. Instead of hard-coding the information, J2EE provides the isUserInRole() method in the HttpServletRequest interface. This method takes a String value representing the security role name used within the application code and returns a boolean value indicating whether the requesting user has been granted that security role. The TravelCustomerServlet illustrated in Listing 4.15 provides an implementation of the doGet() method that uses isUserInRole() .

Listing 4.15. TravelCustomerServlet.java
 import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class TravelCustomerServlet extends HttpServlet {    public void doGet (HttpServletRequest request,       HttpServletResponse response) throws ServletException,       IOException    {       if (request.isUserInRole("PlatinumCust"))          response.sendRedirect("PlatinumCustomer.jsp");       else          response.sendRedirect("Customer.jsp");    } } 

A security role name programmatically referenced within a Web application is called a role reference (see page 67). The Web container must be able to map a Web application's role references to the security role names declared in the Web application's deployment descriptor. This mapping is configured by the Application Assembler in the Web application's deployment descriptor. Listing 4.16 shows a deployment descriptor fragment mapping both the role references PlatinumCust in TravelCustmerServlet and PlatCustomer in TravelOffersServlet to the security role PlatinumCustomer .

Listing 4.16. Mapping Role References to Security Roles
 <servlet>    <servlet-name>TravelCustomer</servlet-name>    <description>       Travel customer specific information    </description>    <servlet-class>TravelCustomerServlet</servlet-class>    <security-role-ref>       <role-name>PlatinumCust</role-name>       <role-link>PlatinumCustomer</role-link>    </security-role-ref> </servlet> <servlet>    <servlet-name>TravelOffers</servlet-name>    <description>Travel deals</description>    <servlet-class>TravelOffersServlet</servlet-class>    <security-role-ref>       <role-name>PlatCustomer</role-name>       <role-link>PlatinumCustomer</role-link>    </security-role-ref> </servlet> 

This deployment descriptor example demonstrates how to use security-role-ref elements to define the mapping between the security role names embedded in a Web application and the security role names that will be used for defining URL authorizations. A security-role-ref element is embedded within a servlet element that specifies a servlet containing a call to the isUserInRole() API. A security-role-ref element contains two entries: role-name and role-link .

  1. The role-name entry within a security-role-ref element refers to the role name String value passed as an argument to isUserInRole() in the application code. The deployment descriptor fragment relevant to TravelCustomerServlet in Listing 4.16 sets the role-name element to PlatinumCust because the TravelCustomerServlet code shown in Lisitng 4.15 calls isUserInRole("PlatinumCust") . In a similar way, the deployment descriptor fragment relevant to the TravelOffersServlet sets the role-name element to PlatCustomer .

  2. Once role-name values have been assigned in the security-role-ref elements, the role references need to be mapped to the security role names used for authorization of Web resources. The role-link elements within the security-role-ref elements allow the Application Assembler to map the security role names that are hard-coded in the application as used in the calls to isUserInRole() to the security role names that are used by the Deployer and the Web container. In the deployment descriptor fragment of Listing 4.16, both role references PlatinumCust and PlatCustomer are mapped to the security role name PlatinumCustomer .

As an example, let us say that the principal calling the servlet TravelCustomerServlet in Listing 4.15 is granted the PlatinumCustomer security role. When the servlet calls isUserInRole("PlatinumCust") , this method call returns true because the deployment descriptor in Listing 4.16 tells the servlet container to map the PlatinumCust role reference to the PlatinumCustomer security role, and the calling principal is granted that security role. However, if the calling principal is not granted the PlatinumCustomer security role, the call to isUserInRole("PlatinumCust") returns false .

It is quite possible that modules developed by various Application Component Providers are bundled into the same J2EE application and its JAR file ”the application's EAR file (see Section 3.2 on page 56). This could potentially generate confusion in the mapping between role references and security role names. For example, in the code of Listing 4.15, the developer uses the term PlatinumCust to refer to a security role associated with a platinum-level customer. Another servlet written by another developer that may also use the same term PlatinumCust to refer to a different security role.

One of the purposes of the security-role-ref element and its role-link subelement is to disambiguate the security role-name values. In fact, the role-link subelement is used to specify the security role name in the deployment environment. Therefore, when two applications use role references intended to have different meanings, different role-link values can be specified to map these role references to different security roles in the deployed environment.

Sometimes, the Application Component Provider and the Application Assembler are the same person. In these cases, you might see that the role-name and the role-link elements have identical values, as shown in Listing 4.17.

Listing 4.17. Example of Identical role-name and role-link Values
 <servlet>    <servlet-name>TravelCustomer</servlet-name>    <description>       Travel customer specific information    </description>    <servlet-class>TravelCustomerServlet</servlet-class>    <security-role-ref>       <role-name>PlatinumCust</role-name>       <role-link>PlatinumCust</role-link>    </security-role-ref> </servlet> 

Mapping identical strings is a redundant step, so it is not necessary to explicitly declare it. Therefore, the deployment descriptor fragment shown in Listing 4.17 is considered to be equivalent to the one in Listing 4.18, where the security-role-ref element is not even declared in the servlet element of the Web module's deployment descriptor.

Listing 4.18. Removing a Redundant security-role-ref Element
 <servlet>    <servlet-name>TravelCustomer</servlet-name>    <description>       Travel customer specific information    </description>    <servlet-class>TravelCustomerServlet</servlet-class> </servlet> 

4.8.3 SSL Attribute Information: Certificates and Cipher Suites

As explained in Section 4.5 on page 113, when connecting over the HTTPS protocol, client-side certificates can be used to establish a mutual-authentication SSL session between an HTTP client and an HTTP server. The client presents an X.509 certificate during the SSL handshake. On completing a successful SSL handshake, the client's identity is mapped to a principal that is assigned to zero or more J2EE security roles. The client is then authorized to access resources, as was described in Section 4.6 on page 125. In addition, the isSecure() method on a ServletRequest object returns true when the request was made using a secure channel, such as HTTPS.

Once the connection has succeeded, enterprise applications may want to access the client's X.509 certificate and other attributes of the SSL session. The value of the subject's DN attribute in the certificate, other information retrieved from the certificate (see Section 4.5.1.3 on page 120), or the cipher suite used to establish the SSL connection can be used to determine the security level of the connection established. To obtain the X.509 certificate programmatically, the getAttribute() method on the ServletRequest object can be queried using the key javax.servlet.request.X509Certificate , as shown in the following line of code:

 java.security.cert.X509Certificate[] certs =    (java.security.cert.X509Certificate[]) request.getAttribute    ("javax.servlet.request.X509Certificate"); 

This method call returns an array of objects of type java.security.cert.X509Certificate . The order of the certificates in the array reflects the ascending order of trust; the first element in the array is the certificate of the client, the second element is the certificate that was used to issue the first certificate (see Section 10.3.4 on page 372), and so on.

Similarly, the getAttribute() method of a ServletRequest object can be used to programmatically obtain other attributes of an SSL session.

  • The size of the key used to establish the SSL connection is obtained by requesting the attribute javax.servlet.request.key_size , as shown in the following line of code:

     Integer keySize = (Integer) request.getAttribute    ("javax.servlet.request.key_size"); 
  • The cipher suite used to establish the SSL connection is obtained by requesting the attribute javax.servlet.request.cipher_suite , as shown in the following line of code:

     String cipherSuite = (String) request.getAttribute    ("javax.servlet.request.cipher_suite"); 

The CertAndCipherSuiteInfo servlet in Listing 4.19 shows how to access client-certificate and SSL-attribute information programmatically.

Listing 4.19. CertAndCipherSuiteInfo.java
 import java.io.PrintWriter; import java.io.IOException; import java.security.cert.X509Certificate; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /**  * This servlet obtains certificate and SSL cipher suite  * information from the client request.  */ public class CertAndCipherSuiteInfo extends HttpServlet {    public void doGet(HttpServletRequest req,       HttpServletResponse res) throws ServletException,       IOException    {       PrintWriter out;       res.setContentType("text/html");       out = res.getWriter();       out.println("<HTML><HEAD><TITLE>SSL Attribute " +          "Information </TITLE></HEAD>" +          "<BODY BGCOLOR=\"#FFFFEE\">");       String cipherSuite = (String) req.getAttribute          ("javax.servlet.request.cipher_suite");       if (cipherSuite != null)       {          X509Certificate certChain[] =             (X509Certificate[]) req.getAttribute             ("javax.servlet.request.X509Certificate");          out.println("<H2>HTTPS Information:</H2>");          out.println("<TABLE BORDER=\"2\" " +             "WIDTH=\"65%\" BGCOLOR=\"#DDDDFF\">");          out.println("<tr><td>Cipher Suite</td><td>" +             cipherSuite + "</td></tr>");          if (certChain != null)             for (int i = 0; i < certChain.length; i++)                out.println("Client Certificate Chain [" +                   i + "] = " + certChain[i].toString());          out.println("</TABLE><BR><BR>");       }       out.println("</BODY></HTML>");    } } 

4.8.4 Programmatic Login

Some scenarios require a servlet to perform a programmatic login ”a servlet-managed authentication ”instead of using the J2EE declarative login configuration to request the user to log in. With programmatic login, servlets should perform the login from within the Web container and access resources based on the authenticated user's identity. Even though JAAS provides authentication APIs (see Section 9.2 on page 291), J2EE V1.3 does not mandate any standard for using JAAS to achieve programmatic login from within a Web container. Containers, including IBM WebSphere Application Server, [4] provide a vendor-specific approach for achieving this functionality.

[4] See http://www.ibm.com/websphere.

 <  Day Day Up  >  


Enterprise Java Security. Building Secure J2EE Applications
Enterprise Javaв„ў Security: Building Secure J2EEв„ў Applications
ISBN: 0321118898
EAN: 2147483647
Year: 2004
Pages: 164

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