Realms and Authentication in Tomcat

Published: Monday, 17 May 2004

JSP authentication can be managed by a servlet container such as Tomcat. The management of authentication and permissions is done by Tomcat. Your web application (your bundle of JSP and servlets) will not need to worry about this, all they need to do is choose which roles can access which pages. This is different to using sessions to keep track of logins like we did in PHP.

We can separate the authentication code and place that responsibility with Tomcat. The servlet specification has more information on container managed security. Individual JSP pages will not have to do any authorisation checking.

The web.xml file, which is distributed as part of your web application, can specify restrictions on certain pages to certain roles. Tomcat’s server.xml is used to specify users that belong to roles. This means that if you move your web application to another server (e.g. JRun) there is a different way to map users and roles.

The authentication can be setup in a number of ways, but the example below is using Tomcat and a PostgreSQL database.

Requirements

As part of our intranet web application there are some timesheet pages that reside in the timesheet/ directory. Ideally, this part of the website should only be accessible by employees.

Choose a Role

The name of the role is simply employee

Create users and roles tables in PostgreSQL

Assume that the intranet database has already been created.

bash-2.05a$ /usr/local/pgsql/bin/psql intranet
Password:
Welcome to psql 7.4.2, the PostgreSQL interactive terminal.

Type:  \copyright for distribution terms
       \h for help with SQL commands
       \? for help on internal slash commands
       \g or terminate with semicolon to execute query
       \q to quit

intranet=# CREATE TABLE users (
intranet(#   username         VARCHAR(15) NOT NULL PRIMARY KEY,
intranet(#   password         CHAR(32) NOT NULL
intranet(# );
NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index "users_pkey" for table "users"
CREATE TABLE
intranet=# CREATE TABLE user_roles (
intranet(#   username         VARCHAR(15) NOT NULL,
intranet(#   role             VARCHAR(15) NOT NULL,
intranet(#   PRIMARY KEY    (username, role),
intranet(#   FOREIGN KEY (username) REFERENCES users(username)
intranet(# );
NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index "user_roles_pkey" for table "user_roles"
CREATE TABLE

Now insert an employee

intranet=# INSERT INTO users VALUES ('test', md5('test'));
INSERT 233820 1

And assign him the role of an employee.

intranet=# INSERT INTO user_roles VALUES ('test', 'employee');
INSERT 233821 1

You now have login, named test with password test inside this database.

Because this is a database, you can write frontends to manage this user list, or even have your web application maintain it.

Add JDBC drivers to Tomcat server.

It is not necessary to add drivers into the web application as the user and roles lookup is done by Tomcat, before a request reaches the web application.

So I copied the PostgreSQL drivers to $CATALINA_HOME</envar>/server/lib/postgresql.jar. Tomcat will automatically add all JAR files found here into its CLASSPATH.

If the web application also wants to use a PostgreSQL database, then the drivers could’ve been placed into $CATALINA_HOME</envar>/common/lib/ instead so they can all have access to it.

Modify Tomcat’s server.xml

This is Tomcat servlet container specific. Inside the Context of your web application, add the following elements

<Context path="/intranet" debug="0" privileged="true"
         docBase="/home/aelst/intranet/web">
  <Logger className="org.apache.catalina.logger.FileLogger"
          prefix="localhost_intranet_log." suffix=".txt"
          timestamp="true"/>
  <Realm className="org.apache.catalina.realm.JDBCRealm" debug="99"
         driverName="org.postgresql.Driver"
         connectionURL="jdbc:postgresql://localhost/intranet?user=dbuser&amp;password=dbpass"
         userTable="users" userNameCol="username" userCredCol="password"
         userRoleTable="user_roles" roleNameCol="role"
         digest="MD5"/>
</Context>

Note that we have added a logger for this web application, it helps us diagnose if something goes wrong.

The Realm element contains all the database information necessary for tomcat to connect to the database, and lookup the appropriate tables and columns to check the passwords. The digest attribute is set to MD5 as that is how the passwords are stored in this database.

Modify the web applications web.xml

The web.xml example below shows that the Timesheets section of the website, located in /timesheets/*, can only be accessed by users with the employee role. The web.xml file is located in WEB-INF/ relative to the Context docBase.

<?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>
  <security-constraint>
    <web-resource-collection>
      <web-resource-name>Timesheets</web-resource-name>
      <url-pattern>/timesheets/*</url-pattern>
    </web-resource-collection>
    <auth-constraint>
       <role-name>employee</role-name>
    </auth-constraint>
  </security-constraint>
  <security-role>
    <role-name>employee</role-name>
  </security-role>
  <login-config>
    <auth-method>BASIC</auth-method>
  </login-config>
</web-app>

The authentication method of BASIC indicates it will use the browser’s default login prompt.

Links

Tomcat 4 realm how to

The example web.xml from the standard tomcat distribution is a well commented file.