Using Web Services

Container-Managed Authentication and Authorization

In the preceding sections, you saw how a web application can use an LDAP directory to look up user information. It is up to the application to use that information appropriately, to allow or deny users access to certain resources. In this section, we discuss an alternative approach: container-managed authentication. This mechanism puts the burden of authenticating users on the application server.

It is much easier to ensure that security is handled consistently for an entire web application if the container manages authentication and authorization. The application programmer can then focus on the flow of the web application without worrying about user privileges.

Most of the configuration details in this chapter are specific to GlassFish and Tomcat, but other application servers have similar mechanisms.

To protect a set of pages, you specify access control information in the web.xml file. For example, the following security constraint restricts all pages in the protected subdirectory to authenticated users who have the role of registereduser or invitedguest.

  <security-constraint>      <web-resource-collection>         <url-pattern>/protected/*</url-pattern>      </web-resource-collection>      <auth-constraint>         <role-name>registereduser</role-name>         <role-name>invitedguest</role-name>       </auth-constraint>   </security-constraint>

The role of a user is assigned during authentication. Roles are stored in the user directory, together with usernames and passwords.

Note

If JSF is configured to use a /faces prefix for JSF pages, then you must add a corresponding URL pattern to the security constraint, such as /faces/protected/* as in the preceding example.


Next, you need to specify how users authenticate themselves. The most flexible approach is form-based authentication. Add the following entry to web.xml:

  <login-config>      <auth-method>FORM</auth-method>       <form-login-config>         <form-login-page>/login.html</form-login-page>         <form-error-page>/noauth.html</form-error-page>      </form-login-config>   </login-config>

The form login configuration specifies a web page into which the user types the username and password. You are free to design any desired appearance for the login page, but you must include a mechanism to submit a request to j_security_check with request parameters named j_username and j_password. The following form will do the job:

  <form method="POST" action="j_security_check">      User name: <input type="text" name="j_username"/>      Password:  <input type="password" name="j_password"/>      <input type="submit" value="Login"/>   </form>

The error page can be any page at all.

When the user requests a protected resource, the login page is displayed (see Figure 10-18). If the user supplies a valid username and password, then the requested page appears. Otherwise, the error page is shown.

Figure 10-18. Requesting a protected resource


Note

To securely transmit the login information from the client to the server, you should use SSL (Secure Sockets Layer). Configuring a server for SSL is beyond the scope of this book. For more information, turn to http://java.sun.com/developer/technicalArticles/WebServices/appserv8-1.html (GlassFish) or http://jakarta.apache.org/tomcat/tomcat-5.5-doc/ssl-howto.html (Tomcat).


You can also specify "basic" authentication by placing the following login configuration into web.xml:

  <login-conf>      <auth-method>BASIC</auth-method>      <realm-name>This string shows up in the dialog</realm-name>   </login-conf>

In that case, the browser pops up a password dialog (see Figure 10-19). However, a professionally designed web site will probably use form-based authentication.

Figure 10-19. Basic authentication


The web.xml file describes only which resources have access restrictions and which roles are allowed access. It is silent on how users, passwords, and roles are stored. You configure that information by specifying a realm for the web application. A realm is any mechanism for looking up usernames, passwords, and roles. Application servers commonly supports several standard realms that access user information from one of the following sources:

  • An LDAP directory

  • A relational database

  • A file (such as Tomcat's conf/tomcat-users.xml)

In GlassFish, you use the administration interface to configure a realm. In the Configuration -> Security -> Realms menu, create a new realm called openldap. Use the default class name and specify the following connection parameters as "additional properties":

  directory: ldap://localhost:389   base-dn: ou=people,dc=corejsf,dc=com   jaas-context: ldapRealm   search-bind-dn: cn=Manager,dc=corejsf,dc=com   search-bind-password: secret   search-filter: uid=%s   group-base-dn: ou=groups,dc=corejsf,dc=com   group-target: cn   group-search-filter: uniqueMember=%d

You also need to supply a file WEB-INF/sun-web.xml, as shown in Listing 10-18. This file maps role names to group names. We use the same names for both.

Listing 10-18. accesscontrol/web/WEB-INF/sun-web.xml (GlassFish only)

  1. <?xml version="1.0" encoding="UTF-8"?>   2.   3. <!DOCTYPE sun-web-app PUBLIC    4.    "-//Sun Microsystems, Inc.//DTD Application Server 9.0 Servlet 2.5//EN"   5.    "http://www.sun.com/software/appserver/dtds/sun-web-app_2_5-0.dtd">   6. <sun-web-app>    7.   8.    <security-role-mapping>   9.       <role-name>registereduser</role-name>  10.       <group-name>registereduser</group-name>  11.    </security-role-mapping>  12.    <security-role-mapping>  13.       <role-name>invitedguest</role-name>  14.       <group-name>invitedguest</group-name>  15.    </security-role-mapping>  16.  17. </sun-web-app>     

To configure a realm in Tomcat, you supply a Realm element. Listing 10-19 shows a typical example, a JNDI realm for an LDAP server.

Listing 10-19. accesscontrol/src/conf/context.xml (Tomcat only)

  1. <Context path="/accesscontrol" docbase="webapps/accesscontrol.war">   2. <Realm className="org.apache.catalina.realm.JNDIRealm"   3.    debug="99"   4.    connectionURL="ldap://localhost:389"   5.    connectionName="cn=Manager,dc=corejsf,dc=com"   6.    connectionPassword="secret"   7.    userPattern="uid={0},ou=people,dc=corejsf,dc=com"   8.    userPassword="userPassword"   9.    roleBase="ou=groups,dc=corejsf,dc=com"  10.    roleName="cn"  11.    roleSearch="(uniqueMember={0})"/>  12. </Context>

The configuration lists the URL and login information, and describes how to look up users and roles. The Realm element is placed inside a Context element in the file context.xml. This is the preferred mechanism for supplying an application-specific realm in Tomcat.

Caution

You can also configure a realm in the Engine or Host element of the server.xml file. However, that realm is then used by the manager application in addition to your regular web application. If you want to use the manager application to install your web applications, then you must make sure that the username and password that you use for installation is included in the realm, with a role of manager.


Since the application server is in charge of authentication and authorization, there is nothing for you to program. Nevertheless, you may want to have pro-grammatic access to the user information. The HttpServletRequest yields a small amount of information, in particular, the name of the user who logged in. You get the request object from the external context:

  ExternalContext external       = FacesContext.getCurrentInstance().getExternalContext();   HttpServletRequest request       = (HttpServletRequest) external.getRequest();   String user = request.getRemoteUser();

You can also test whether the current user belongs to a given role. For example,

  String role = "admin";   boolean isAdmin = request.isUserInRole(role);

Note

Currently, there is no specification for logging off or for switching identities when using container-managed security. This is a problem, particularly for testing web applications. GlassFish and Tomcat use cookies to represent the current user. You need to quit and restart your browser (or at least clear personal data) whenever you want to switch your identity. We resorted to using Lynx for testing because it starts up much faster than a graphical web browser (see Figure 10-20).


Figure 10-20. Using Lynx for testing a web application


We give you a skeleton application that shows container-managed security at work. When you access the protected resource protected/welcome.jsp (Listing 10-20), then the authentication dialog of Listing 10-21 is displayed. You can proceed only if you enter a username and password of a user belonging to the registereduser or invitedguest role.

Upon successful authentication, the page shown in Figure 10-21 is displayed. The welcome page shows the name of the registered user and lets you test for role membership.

Figure 10-21. Welcome page of the authentication test application


Listing 10-20. accesscontrol/web/protected/welcome.jsp

  1. <html>   2.    <%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>   3.    <%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>   4.    <f:view>   5.       <head>   6.          <title><h:outputText value="#{msgs.title}"/></title>   7.       </head>   8.       <body>   9.          <h:form>  10.             <p><h:outputText value="#{msgs.youHaveAccess}"/></p>  11.             <h:panelGrid columns="2">  12.                <h:outputText value="#{msgs.yourUserName}"/>  13.                <h:outputText value="#{user.name}"/>  14.  15.                <h:panelGroup>  16.                   <h:outputText value="#{msgs.memberOf}"/>  17.                   <h:selectOneMenu onchange="submit()" value="#{user.role}">  18.                      <f:selectItem itemValue="" itemLabel="Select a role"/>  19.                      <f:selectItem itemValue="admin" itemLabel="admin"/>  20.                      <f:selectItem itemValue="manager" itemLabel="manager"/>  21.                      <f:selectItem itemValue="registereduser"   22.                         itemLabel="registereduser"/>  23.                      <f:selectItem itemValue="invitedguest"   24.                         itemLabel="invitedguest"/>  25.                   </h:selectOneMenu>  26.                </h:panelGroup>  27.                <h:outputText value="#{user.inRole}"/>  28.             </h:panelGrid>  29.          </h:form>  30.       </body>  31.    </f:view>  32. </html>     

Listing 10-21. accesscontrol/web/login.html

  1. <html>   2.    <head>   3.       <title>Login Form</title>   4.    </head>   5.   6.    <body>   7.       <form method="post" action="j_security_check">   8.          <p>You need to log in to access protected information.</p>   9.          <table>  10.             <tr>  11.                <td>User name:</td>  12.                <td>  13.                   <input type="text" name="j_username"/>  14.                </td>  15.             </tr>  16.             <tr>  17.                <td>Password:</td>  18.                <td>  19.                   <input type="password" name="j_password"/>  20.                </td>  21.             </tr>  22.          </table>  23.          <input type="submit" value="Login"/>  24.       </form>  25.    </body>  26. </html>     

Figure 10-22 shows the directory structure of the application. The web.xml file in Listing 10-22 restricts access to the protected directory. Listing 10-23 contains the page that is displayed when authorization fails. Listing 10-20 contains the protected page. You can find the code for the user bean in Listing 10-24 and the message strings in Listing 10-25.

Figure 10-22. Directory structure of the access control application


Listing 10-22. accesscontrol/web/WEB-INF/web.xml

  1. <?xml version="1.0"?>   2. <web-app xmlns="http://java.sun.com/xml/ns/javaee"   3.    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"   4.    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee   5.       http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"   6.    version="2.5">   7.    <servlet>   8.       <servlet-name>Faces Servlet</servlet-name>   9.       <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>  10.       <load-on-startup>1</load-on-startup>  11.    </servlet>  12.  13.    <servlet-mapping>  14.       <servlet-name>Faces Servlet</servlet-name>  15.       <url-pattern>*.faces</url-pattern>  16.    </servlet-mapping>  17.  18.    <welcome-file-list>  19.      <welcome-file>index.html</welcome-file>  20.    </welcome-file-list>  21.  22.    <security-constraint>  23.       <web-resource-collection>  24.          <web-resource-name>Protected Pages</web-resource-name>  25.          <url-pattern>/protected/*</url-pattern>  26.       </web-resource-collection>  27.       <auth-constraint>  28.          <role-name>registereduser</role-name>  29.          <role-name>invitedguest</role-name>  30.       </auth-constraint>  31.     </security-constraint>  32.  33.    <login-config>  34.       <auth-method>FORM</auth-method>   35.       <realm-name>openldap</realm-name>  36.       <form-login-config>  37.          <form-login-page>/login.html</form-login-page>  38.          <form-error-page>/noauth.html</form-error-page>  39.       </form-login-config>  40.    </login-config>  41.  42.     <security-role>  43.       <role-name>registereduser</role-name>  44.     </security-role>  45.      <security-role>  46.        <role-name>invitedguest</role-name>  47.     </security-role>  48. </web-app>     

Listing 10-23. accesscontrol/web/noauth.html

  1. <html>   2.    <head>   3.       <title>Authentication failed</title>   4.    </head>   5.   6.     <body>   7.        <p>Sorry--authentication failed. Please try again.</p>   8.     </body>   9.  </html>

Listing 10-24. accesscontrol/src/java/com/corejsf/UserBean.java

  1. package com.corejsf;   2.   3. import java.util.logging.Logger;   4. import javax.faces.context.ExternalContext;   5. import javax.faces.context.FacesContext;   6. import javax.servlet.http.HttpServletRequest;   7.   8. public class UserBean {   9.    private String name;  10.    private String role;  11.    private Logger logger = Logger.getLogger("com.corejsf");  12.  13.    public String getName() {   14.       if (name == null) getUserData();   15.       return name == null ? "" : name;   16.    }  17.  18.    public String getRole() { return role == null ? "" : role; }  19.    public void setRole(String newValue) { role = newValue; }  20.  21.    public boolean isInRole() {   22.       ExternalContext context   23.          = FacesContext.getCurrentInstance().getExternalContext();  24.       Object requestObject =  context.getRequest();  25.       if (!(requestObject instanceof HttpServletRequest)) {  26.          logger.severe("request object has type " + requestObject.getClass());  27.          return false;  28.       }  29.       HttpServletRequest request = (HttpServletRequest) requestObject;  30.       return request.isUserInRole(role);  31.    }  32.  33.    private void getUserData() {  34.       ExternalContext context   35.          = FacesContext.getCurrentInstance().getExternalContext();  36.       Object requestObject =  context.getRequest();  37.       if (!(requestObject instanceof HttpServletRequest)) {  38.          logger.severe("request object has type " + requestObject.getClass());  39.          return;  40.       }  41.       HttpServletRequest request = (HttpServletRequest) requestObject;  42.       name = request.getRemoteUser();  43.    }  44. }     

Listing 10-25. accesscontrol/src/java/com/corejsf/messages.properties

  1. title=Authentication successful   2. youHaveAccess=You now have access to protected information!   3. yourUserName=Your user name   4. memberOf=Member of

javax.servlet.HttpServletRequest

  • String getRemoteUser() Servlet 2.2

    Gets the name of the user who is currently logged in, or null if there is no such user.

  • boolean isUserInRole(String role) Servlet 2.2

    Tests whether the current user belongs to the given role.



Core JavaServerT Faces
Core JavaServer(TM) Faces (2nd Edition)
ISBN: 0131738860
EAN: 2147483647
Year: 2004
Pages: 84

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