A simple example of Tomcat Realms and Security

Last week a colleague of mine called me up because he was struggling with setting up Tomcat JDBCRealm for use with a relatively simple straightforward webapp. Wed recently released the 1.0 version of GateKeeper, and he wanted to use it to manage his users and roles. The GateKeeper side of things went just fine, but the JDBCRealm setup on his webapp was proving very balky.

He fired up VNC, and I logged in and checked out his settings. And there was nothing wrong! At least, nothing that looked odd in any way. We then googled for some help, maybe a simple sample setup, but to no avail! Oddly enough, nowhere on the internet is a good example of using a Tomcat Realm to protect a webapp. There are various examples, but they just show a part of the puzzle, maybe just the section in the web.xml, or a Realm definition: . Reading the servlet spec for web.xml helps, but doesnt give you details on the Tomcat specific details.

So, over the weekend I set out to create a simple example, and I planned on using the jsp-examples app the ships with Tomcat. After poking around jsp-examples I discovered what I had been looking for all along! There is a full example of protecting a webapp using a Realm! The example for some odd reason is NOT linked from the home page of jsp-examples, but it is there. http://localhost:8080/security/protected and log in as user role1, with the password tomcat.

Ill walk you really quickly through the relevant portions of the configuration files. First off you define what URLs you want protected by which roles in your web-apps web.xml file:

Example Security ConstraintProtected Area/security/protected/*DELETEGETPOSTPUTtomcatrole1FORMExample Form-Based Authentication Arearole1tomcat

The first stanza specifies the URLs of the pages that we want to protect, as well as what roles are required to allow access. Anything in the /security/protected/* pattern will require the user has either the role role1 or tomcat.

The next stanza, specifies how you gain access to the protected URLs. In this example, we are using FORM based security, so we specify the URLs for the login/logout pages. If you are using BASIC authentication then your stanza is much simpler:

BASICExample BASIC Authentication Area

The remaining stanzas, are the roles that are used in this webapp, and they are elements that are often forgotten in a web.xml.

Now that we have defined that only users who have roles role1 or tomcat can access the application, we then need to configure Tomcat. This is done through server.xml, and can be a bit of a rat hole to figure everything out. So, extracted from server.xml we have the following XML stanzas. Ive removed most of the commenting so you can see the overall structure of the document:

Now, instead of going from top to bottom, well start from the definition for the specific host, and work our way out. The challenge that my colleague and I had was that we thought we needed to somehow map a in the web.xml to some sort of definition in server.xml. We were mucking around with all sorts of stanzas embedded in stanzas and trying to match in the web.xml to the element in server.xml. What we didnt realize until I found the jsp-examples sample security code is that because the realm is defined inside of the stanza, it applies to all hosts! And that there is NO explicit mapping between webapps and realms at a level more detailed then at an Engine level. All webapps defined in all hosts that share the same engine share the same realm! So the complete stanza looks like:

Now, I dont know what you would do if you wanted to use different Realms for each webapp, maybe define multiple Engines I guess. Our UserDatabaseRealm is not fully defined here, instead it refers to a global resource called UserDatabase. That is defined outside in our stanza:

Weve defined a resource call UserDatabase that reads in data in the conf/tomcat-users.xml file and exposes it as a user database.

Hopefully this will walk you through all the setup steps required for adding a Realm to your webapp. For me, the key insight was that the realm definition inside of the engine definition applies to all the web-apps in all the hosts. I am working on cutting our 1.0.1 version of Gatekeeper which will demo using a JDBCRealm. I will post a follow up on that.