8.1 HTTP Authentication

Java Servlet Programming, 2nd Edition > 8. Security > 8.1 HTTP Authentication

 
< BACKCONTINUE >

8.1 HTTP Authentication

As we discussed briefly in Chapter 4, the HTTP protocol provides built-in authentication support called basic authentication based on a simple challenge/response, username/password model. With this technique, the web server maintains a database of usernames and passwords and identifies certain resources (files, directories, servlets, etc.) as protected. When a user requests access to a protected resource, the server responds with a request for the client's username and password. At this point, the browser usually pops up a dialog box where the user enters the information, and that input is sent back to the server as part of a second authorized request. If the submitted username and password match the information in the server's database, access is granted. The whole authentication process is handled by the server itself.

Basic authentication alone is very weak. It provides no confidentiality, no integrity, and only the most basic authentication. The problem is that passwords are transmitted over the network, thinly disguised by a well-known and easily reversed Base64 encoding. Anyone monitoring the TCP/IP data stream has full and immediate access to all the information being exchanged, including the username and password, unless there is additional SSL encryption employed (as discussed later in the chapter). Plus, passwords are often stored on the server in clear text, making them vulnerable to anyone cracking into the server's filesystem. While it's certainly better than nothing, sites that rely exclusively on basic authentication cannot be considered really secure.

Digest authentication is a variation on the basic authentication scheme. Instead of transmitting a password over the network directly, a digest of the password is used instead. The digest is produced by taking a hash (using the very secure MD5 encryption algorithm) of the username, password, URI, HTTP request method, and a randomly generated nonce value provided by the server. Both sides of the transaction know the password and use it to compute digests. If the digests match, access is granted. Transactions are thus somewhat more secure than they would be otherwise because digests are valid for only a single URI request and nonce value. The server, however, must still maintain a database of the original passwords. And, as of this writing, digest authentication is not supported by very many browsers.

The moral of the story is that HTTP authentication can be useful in low-security environments. For example, a site that charges for access to content say, an online newspaper is more concerned with ease of use and administration than lock-tight security, so HTTP authentication is often sufficient.

8.1.1 Configuring HTTP Authentication

In versions of the Servlet API before 2.2, the technique for configuring authentication varied depending on the server. Beginning with API 2.2, the technique has been standardized and now configuration of security policies can be accomplished in a portable manner using the web.xml deployment descriptor.

Before we begin, there are two caveats to this portability. First, a web server is not required to implement the Servlet API 2.2 security mechanism to be considered Servlet API 2.2 compliant. Implementing the full security portion of the specification is quite involved, and a servlet container is allowed to implement only a portion of the security mechanism, or even none at all. The only servers required to implement the full security mechanism are those wishing to be compliant with the more advanced Java 2, Enterprise Edition (J2EE) specification, of which the Servlet API is but one part. Second, security is one of the newest and least understood aspects of Servlet API 2.2, and web servers have varied somewhat on their implementations of these mechanisms. Over time that will settle down, but in the meanwhile, to ensure your site remains secure, make sure you test everything at least once when migrating between servers.

8.1.1.1 Role-based authentication

Using tags in the web application deployment descriptor, security constraints can be set up to indicate that certain pages in the web application are to be accessed only by users with certain credentials. Servlets use role-based authorization to manage access. With this model, access permissions are granted to an abstract entity called a security role , and access is allowed only to users or groups of users who are part of that given role. For example, you might want to set up your site so that pages that display salary information are restricted to only those users who are in a "manager" role.

The deployment descriptor specifies the type of access granted to each role, but does not specify that role to user or group mapping. That's done during deployment of the application, using server-specific tools. The ultimate mapping may come from many locations text files, database tables, the operating system, and so on.

8.1.1.2 Restricting access to a servlet

For a concrete example, let's assume we have a servlet that needs restricted access, as shown in Example 8-1. (Servlets aren't the only things that can be protected static files and anything else can be as well but somehow it seems appropriate in this book to use a servlet as our example.)

Example 8-1. Are You Sure You Have Permissions to Read This Example?
import java.io.*; import javax.servlet.*; import javax.servlet.http.*; public class SalaryServer extends HttpServlet {   public void doGet(HttpServletRequest req, HttpServletResponse res)                                throws ServletException, IOException {     res.setContentType("text/plain");     PrintWriter out = res.getWriter();     out.println("Top-secret information:");     out.println("Everyone else gets paid more than you!");   } }

Let's also assume that you have a user database for your server that contains a list of usernames, passwords, and roles. Remember, not all servers provide this, and those that do are free to implement the user database however they see fit. For Tomcat 3.2 you specify users in the conf/tomcat-users.xml file as shown in Example 8-2. (Future Tomcat versions are likely to have a more secure storage format than plain text in an XML file.)

Example 8-2. Tomcat's conf/tomcat-users.xml File
<tomcat-users>   <user name="Dilbert"      password="dnrc"         roles="engineer" />   <user name="Wally"        password="iluvalice"    roles="engineer,slacker" />   <user name="MrPointyHair" password="MrPointyHair" roles="manager,slacker" /> </tomcat-users>

Notice MrPointyHair is the only user who belongs to the manager role. Assuming he figures out how to connect his Etch-A-Sketch computer to the Web, he should be the only employee with permission to access our secret servlet. We specify that rule with the web.xml file shown in Example 8-3.

Remember, the order of the tags in a web.xml file does matter. Always follow this order: <security-constraint> , <login-config>, then <security-role>. Order of the tags within these elements matters as well.

This example may look a bit complicated. Security is one place where it's often easiest to use a graphical tool as an aid in creating web.xml files.

Example 8-3. Restricting Access with Basic Authentication
<?xml version="1.0" encoding="ISO-8859-1"?> <!DOCTYPE web-app     PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN"     "http://java.sun.com/j2ee/dtds/web-app_2_2.dtd"> <web-app>     <servlet>         <servlet-name>             secret         </servlet-name>         <servlet-class>             SalaryServer         </servlet-class>     </servlet>     <security-constraint>         <web-resource-collection>             <web-resource-name>                 SecretProtection             </web-resource-name>             <url-pattern>                 /servlet/SalaryServer             </url-pattern>             <url-pattern>                 /servlet/secret             </url-pattern>             <http-method>                 GET             </http-method>             <http-method>                 POST             </http-method>         </web-resource-collection>         <auth-constraint>             <role-name>                 manager             </role-name>         </auth-constraint>     </security-constraint>     <login-config>         <auth-method>             BASIC       <!-- BASIC, DIGEST, FORM, CLIENT-CERT -->         </auth-method>         <realm-name>             Default     <!-- optional, only useful for BASIC -->         </realm-name>     </login-config>     <security-role>         <role-name>             manager         </role-name>     </security-role> </web-app>

This deployment descriptor protects all GET and POST access to /servlet/secret and /servlet/SalaryServer so that only users in the role manager who have logged in using basic authentication are allowed access. The rest of the site remains unrestricted.

It works like this: the <security-constraint> tag protects a <web-resource-collection> so that access is granted only for roles in the <auth-constraint>. Each <web-resource-collection> contains a name, any number of URL patterns specifying the URLs to protect, and any number of HTTP methods for which access should be restricted. The name must be specified even though it's really useful only for tools. For URL patterns you can use the same wildcards you use for servlet mapping, as discussed in Chapter 2. For HTTP methods you should usually specify at least GET and POST; if no <http-method> entries are specified, then all methods are protected. The <auth-constraint> tag holds any number of roles that are to be granted access to the resource collection.

The <login-config> tag specifies the login methodology to be used by this application. In this case, we specify basic authentication in the Default realm. The <auth-method> tag allows BASIC , DIGEST, FORM, and CLIENT-CERT values representing authentication types of Basic, Digest, form-based, and client-side certificates, respectively. We'll talk about form-based and client-side certificates later in the chapter. The <realm-name> tag specifies the login realm to use (since a server may manage different user lists for different realms); it has meaning only for Basic and Digest authentication.

Finally, the <security-role> tag holds a list of roles that may be used by this application. Explicitly declaring the roles to be used supports tool-based manipulations of the file.

The security rules are fairly limited. For example, there's no way to allow access by all users except those in a "blacklist" role. The closest solution would be to have an approved list role that the server mapped to all users not in some group.

Now that we have this web.xml file in place, the server will catch all requests for the given URL patterns that use the given HTTP methods and check for client credentials. If the credentials are valid and the user maps (in a server-specific way) to the manager role, then access is granted. If the credentials are invalid or if the user is not in the manager role, then access is denied and a browser pop-up window will ask the user to try again.

8.1.2 Retrieving Authentication Information

A servlet can retrieve information about the server's authentication using two methods introduced in Chapter 4: getRemoteUser( ) and getAuthType( ). The Servlet API 2.2 also includes a new method, getUserPrincipal( ) , that returns an object implementing the java.security.Principal interface:

public java.security.Principal HttpServletRequest.getUserPrincipal()

A principal is the technical term for the entity being authenticated. It may be a user, group, corporation, or just a generic login ID. The Principal interface includes a getName( ) method that returns the principal's name. The getUserPrincipal( ) method is the preferred way to determine the authenticated user's identity, while getRemoteUser( ) is primarily for CGI compatibility. The isUserInRole( ) method was also introduced in Servlet API 2.2. This method returns true only if the authenticated user belongs to the specified role:

public boolean HttpServletRequest.isUserInRole(String role)

This method allows a certain amount of decision making to be done within a servlet itself. For example, assume a deployment descriptor allows access to a servlet by many different roles. Calling this method allows the servlet to vary its runtime behavior depending on the authenticated user's role.

Any number of role aliases can be created in the deployment descriptor, so that from a servlet's perspective, a query on the role mgr would be the same as a query on the role manager. This proves especially useful when integrating servlets from web applications that may use different role names than those in this web application. Aliases are configured per servlet, using the <security-role-ref> tag inside the <servlet> tag, as shown in the following web.xml snippet:

    <servlet>         <servlet-name>             secret         </servlet-name>         <servlet-class>             SalaryViewer         </servlet-class>         <security-role-ref>             <role-name>                 mgr        <!-- name used by servlet -->             </role-name>             <role-link>                 manager    <!-- name used in deployment descriptor -->             </role-link>         </security-role-ref>     </servlet>

Any number of <security-role-ref> tags may exist for a servlet. Remember that these aliases are valid only when accessing the servlet under its registered name.

Example 8-4 shows a simple servlet that tells the client its name, its principal, the kind of authentication performed (BASIC, DIGEST, FORM, CLIENT-CERT), and whether the user is a manager. To see this servlet in action, you should install it in your web server and protect it with a security scheme as shown in the previous section (making sure to restrict access to this new <url-pattern>).

Example 8-4. Snooping the Authentication Information
import java.io.*; import java.security.*; import javax.servlet.*; import javax.servlet.http.*; public class AuthenticationSnoop extends HttpServlet {   public void doGet(HttpServletRequest req, HttpServletResponse res)                                throws ServletException, IOException {     res.setContentType("text/html");     PrintWriter out = res.getWriter();     out.println("<HTML><HEAD><TITLE>AuthenticationSnoop</TITLE></HEAD><BODY>");     out.println("<H1>This is a password protected resource</H1>");     out.println("<PRE>");     out.println("User Name: " + req.getRemoteUser());     String name = (req.getUserPrincipal() == null) ?                    null : req.getUserPrincipal().getName();     out.println("Principal Name: " + name);     out.println("Authentication Type: " + req.getAuthType());     out.println("Is a Manager: " + req.isUserInRole("manager"));     out.println("</PRE>");     out.println("</BODY></HTML>");   } }

The resulting output looks something like this:

This is a password protected resource User Name: jhunter Principal Name: jhunter Authentication Type: BASIC Is a Manager: false


Last updated on 3/20/2003
Java Servlet Programming, 2nd Edition, © 2001 O'Reilly

< BACKCONTINUE >


Java servlet programming
Java Servlet Programming (Java Series)
ISBN: 0596000405
EAN: 2147483647
Year: 2000
Pages: 223

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