{scrollbar}

Apache Tomcat

22list

Description

A common task when developing a web application is user authentication and authorization - parts of the application should only be seen by the users which you want to see them. Three things are required for realizing this, a mechanism for authentication which checks the credentials provided by the user in the login form. A mechanism for authorization which decides about user privileges and a data store where user information & credentials are stored.
A perfect choice for the data store is ApcheDS. LDAP is a widely adopted standard so you can reuse your user data also for other systems.
For authentication and authorization J2EE provides a few standard mechanisms. The most popular mechanism for authentication, and the one used in the example, is form based authentication, where you can create your own customized JSP login form. There exist
three further authentication mechanisms which are not discussed here, so look at the resources if you are interested in.
So let's talk about authorization. In a J2EE environment it's possible to assign one or more roles to each user. A role is a logical grouping of users, for example you could have different roles for employees, customers and guests. Basing on these roles you can grant different rights on what you allow your users to see and to do.
The following example shows the building of a simple web application where you can Login using username and password and afterwards receive a page confirming your successful login and presenting details about it.

Example

Prerequisites:

  • Tomcat 5.5 (this example was tested with 5.5.20 but should work with every 5.5.x version)
  • ApacheDS

Configuration used in this example:

Tomcat

 

Host

madagaskar

Port

8080

ApacheDS

 

Host

zanzibar

Port

10389

Suffix

o=sevenSeas

Admin user dn

uid=admin,ou=system

Admin pass

secret

Data
First import the example data in an own partition of your directory server, you can find them here, if you haven't already done this. How to create a partition is described here, how to import data into the directory is described here. This should result in the following directory structure:

Download the archive with the JSP files for this example, (which are taken from an tomcat example) and extract it to the webapps folder of your tomcat installation.

Deployment Descriptor
The archive doesn't contain a deployment descriptor (DD) for Tomcat, hence we have to create one for our application. The DD defines which part of our application we wish to protect, whom we want grant access to it, which authentication method should be used and other things, but it does not define the details for connecting to ApacheDS. In our example, we want to grant only the crew of "HMS Bounty" access to our application. The DD is stored at /security/WEB-INF/web.xml.

xml <?xml version="1.0" encoding="ISO-8859-1"?> <web-app xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd" version="2.4"> <security-constraint> <web-resource-collection> <web-resource-name>Protected Area</web-resource-name> <!-- Define the context-relative URL(s) to be protected --> <url-pattern>/protected/*</url-pattern> </web-resource-collection> <auth-constraint> <!-- Anyone with one of the listed roles may access this area --> <role-name>HMS Bounty</role-name> </auth-constraint> </security-constraint> <!-- Default login configuration uses form-based authentication --> <login-config> <auth-method>FORM</auth-method> <form-login-config> <form-login-page>/protected/login.jsp</form-login-page> <form-error-page>/protected/error.jsp</form-error-page> </form-login-config> </login-config> <!-- Security roles referenced by this web application --> <security-role> <role-name>HMS Bounty</role-name> </security-role> </web-app>

Let's have a closer look at it.

xml <url-pattern>/protected/*</url-pattern>

This describes which url should be protected, which means, that the url's defined here can only been requested by a user who has successfully been authenticated (and has an appropriate role assigned). You can provide multiple patterns here. It's also possible to restrict access only for specific HTTP Methods. Which roles are allowed to request these restricted URL's is defined in the following lines. You can specify either some concrete role names here, in our example "HMS Bounty", or just write "*" to allow access for all registered users.

xml <role-name>HMS Bounty</role-name>

The login-config element provides details about the authentication method you want to use. This example uses form-based authentication, so we need to define the authentication method "FORM" and the location for our login and error pages.

xml <login-config> <auth-method>FORM</auth-method> ... </login-config>

The security-role element lists all roles available.

JNDI Realm
The details for the connection to ApacheDS are defined using a Tomcat JNDI Realm. Save the following in a file at /security/protected/META-INF/context.xml

xml <?xml version="1.0" encoding="UTF-8"?> <Context path="/jsp-examples/*" > <Realm className="org.apache.catalina.realm.JNDIRealm" debug="99" connectionName="uid=admin,ou=system" connectionPassword="secret" connectionURL="ldap://zanzibar:10389" roleBase="ou=crews,ou=groups,o=sevenSeas" roleName="cn" roleSearch="(uniqueMember={0})" roleSubtree="false" userPassword="userPassword" userPattern="cn={0},ou=people,o=sevenSeas" /> </Context>

Let's have a closer look at it. The following specifies the details for the user connecting to ApacheDS. Make sure that this user has the appropriate rights for reading all required entries and attributes. We have used the admin credentials here, but in general it's not a good idea to provide your admin credentials everywhere in your config files. We have done this here because it's only a very simple example.

xml connectionName="uid=admin,ou=system" connectionPassword="secret" connectionURL="ldap://zanzibar:10389"

But the question is: How does Tomcat figure out where the entries for the user's you want to allow to login are stored?

xml userPassword="userPassword" userPattern="cn={0},ou=people,o=sevenSeas"

The attribute "userPassword" contains the name of the attribute, which contains the password of the user. "userPattern" specifies where to search for user entries. The expression "{0}" is a placeholder for the value of the username entered by the user into the login form.

Finally you have to tell Tomcat how he can determine if someone is member of the crew from HMS Bounty. All members of the crew are stored in a groupOfUniqueNames entry below "ou=crews,ou=groups,o=sevenSeas".

xml roleBase="ou=crews,ou=groups,o=sevenSeas" roleName="cn" roleSearch="(uniqueMember={0})" roleSubtree="false"

Starting the application
Now (re)start Tomcat and go to http://madagaskar:8080/security/protected/index.jsp. You should see the following Login Form. Enter name and password (which is simply "pass" in our example) of a member of the crew of HMS Bounty.

After successful login you can test of your user belongs to a specific role.

Login Form
If you have a closer look at the source of the login form (/security/protected/login.jsp) you'll see the following

html <form method="POST" action="j_security_check" > ... <input type="text" name="j_username"> ... <input type="password" name="j_password"> ... </form>

It's always crucial that the Login Form has the action "j_security_check" and that the fields "j_username" and "j_password" are present, otherwise Form-Based authentication won't work properly. This and further details are explained in the J2EE Tutorial and servlet specification.

Resources

Tomcat's Homepage
Realms in Tomcat
The J2EE 1.4 Tutorial (Chapter 32 contains more information about J2EE security)
Servlet Specification 2.4 (the one which belongs to J2EE 1.4)

  • No labels