h2. User database for Apache Tomcat In this section you will learn how to use Apache Directory Server as a user registry for a web application server. ApacheDS holds the user data (user IDs and credentials, groups) and performs authentication. h3. Some background A common task when developing a web application is user authentication and authorization. Parts of the application (or even the application as a whole) should only be seen by privileged users. In order to achieve this, three things are required * a mechanism for authentication, which checks the credentials provided by the user (e.g. in a login form) * a mechanism for authorization, which decides about user privileges and * a data store where user information and credentials are stored For authentication and authorization Java EE (formerly known as J2EE) provides a few standard mechanisms. A good choice for the data store is ApacheDS. LDAP is a widely adopted standard so you can reuse your user data also for other systems. h4. Apache Tomcat According to the project's [Homepage|http://tomcat.apache.org|tomcat.apache.org], "Apache Tomcat is the servlet container that is used in the official Reference Implementation for the Java Servlet and JavaServer Pages technologies. The Java Servlet and JavaServer Pages specifications are developed by Sun under the Java Community Process". !tomcat-logo.png! It is quite common to use Tomcat as runtime environment for Java web applications. Applications, which are created with the help of standard technologies like Servlets, JSPs and JavaServer Faces, or web frameworks like Apache Struts. Apache Tomcat is used as an example here, but the configuration for other server solutions (HTTP servers among others) is quite comparable. h3. Prerequisites h4. Server (Apache Directory Server) The following assumes that ApacheDS 2.0 is configured as described [here|1.4. About the sample configurations and sample directory data]. The sample partition "o=sevenSeas" including the sample data should be configured and filled. If this does not hold true to your situation: No problem. But you have to adjust the configuration parameters according your environment. Note that anonymous access to ApacheDS is used here. This leads to the simplest configuration. If you don't want to allow anonymous access, you will have to use a bind user within the Tomcat configuration (see notes below). h4. Client (Apache Tomcat) Although a server application, Tomcat acts as an LDAP client here. It may run on another computer, hostname _madagascar_ is used within the following. The configuration was tested with Apache Tomcat 6.0.14 on Java 5, but other Tomcat versions (even older ones like 5.X) should work as well, because this part of the documentation has not changed. h3. About this example In order to demonstrate how ApacheDS works as a user registry, we will use the built in [Manager application|http://tomcat.apache.org/tomcat-6.0-doc/manager-howto.html|tomcat.apache.org] of Tomcat. This saves us to create our own web application for demonstration purposes. The manager application is used for administration and deployment tasks. It's security configuration, as usual described in the deployment descriptor of the web applications _web.xml_ contains the following lines: {noformat} ... HTMLManger and Manager command /jmxproxy/* /html/* ... manager BASIC Tomcat Manager Application The role that is required to log in to the Manager Application manager ... {noformat} The security constraints enforce that only authenticated users with role _manager_ are able to use the application. Furthermore the declarations enforce authentication with the _HTTP Basic_ mechanism, as defined in [RFC 2617|http://tools.ietf.org/html/rfc2617|tools.ietf.org] ("HTTP Authentication: Basic and Digest Access Authentication"). Anyway, the configuration as depicted here will work for all applications which take advantage of the Java EE security mechanism for web applications. This holds true for your own applications as well, if you leverage the security mechanism of Java EE. Learn more about this, for instance in the [Java EE 5 Tutorial|http://java.sun.com/javaee/5/docs/tutorial/doc/bncas.html|java.sun.com] at Sun. h3. Preparing the sample directory for the example As described above, users of the application must have the _manager_ role. Because we do not want to modify the configuration of the web application, we introduce a new group _manager_ into our directory. We therefore create the following two entries within the sample partition. Download the LDIF data [here|^tomcat_manager.ldif|tomcat_manager.ldif], and import it with Apache Directory Studio or any other capable LDAP client. {noformat} dn: ou=tomcat,ou=groups,o=sevenSeas ou: tomcat objectClass: organizationalUnit objectClass: top description: Tomcat groups dn: cn=manager,ou=tomcat,ou=groups,o=sevenSeas objectClass: groupOfNames objectClass: top cn: manager member: cn=Horatio Hornblower,ou=people,o=sevenSeas {noformat} Horatio Hornblower is the only member of the _manager_ group. He should therefore be the only one who is able to use the application, if configuration is finished. After creation of the two new entries, the partition looks like this. !studio_groups.png! h3. Tomcat configuration Enter Tomcat. It has a concept called [Realm|http://tomcat.apache.org/tomcat-6.0-doc/realm-howto.html|tomcat.apache.org] for user registries. Different implementations exist for different data stores. The one designated to LDAP is called _JNDIRealm_. In order to use our ApacheDS as user data storage, edit the _server.xml_ configuration file of your Tomcat instance (located in _/conf_). You can comment out other realms and add a _JNDIRealm_ within the _Engine_ element like this: {noformat} ... ... ... ... {noformat} Note that this realm, if placed within will rule the whole Tomcat instance. Other scopes are possible as well, feel free to learn more about this topic from the pache Tomcat [Realm Configuration HOW-TO|http://tomcat.apache.org/tomcat-6.0-doc/realm-howto.html|tomcat.apache.org]. Download the _server.xml_ used for our tests [here|^server.xml|server.xml]. Let's look how this configuration works. h4. Connectivity The _connectionURL_ attribute holds the connection data (hostname, port, base DN) to our ApacheDS as an LDAP URL. Tomcat will bind to the server anonymously. It is possible to use a technical user as well (attributes _connectionName_, _connectionPassword_, see Tomcat Realm documentation for details). h4. Authentication If configured like this, Tomcat will perform exactly the steps described in [3.1. Authentication options] (see "How to authenticate a user by uid and password?") in order to authenticate a user. First of all, Tomcat searches anonymously the entry of the user with the help of an LDAP search operation. The following parameters of the _JNDIRealm_ configuration above govern the search: || Parameter || Value in example || Comments || |userBase|ou=people|Search base. Combined with the connection parameter, this leads to "ou=people,o=sevenSeas"| |userSearch|(&(objectClass=inetOrgPerson)(uid=\{0\}))|Search filter. Use '&' instead of '&' due to XML. '\{0\}' will be replaced by Tomcat with the given user ID | |userSubtree|true|Search the whole subtree | You can perform the corresponding search with an arbitrary LDAP client. This method is a good practice in case of trouble shooting. This is how it looks with a command line tool: {noformat} $ ldapsearch -h zanzibar -p 10389 -b "ou=people,o=sevenSeas" \\ -s sub "(&(objectClass=inetOrgPerson)(uid=hhornblo))" cn version: 1 dn: cn=Horatio Hornblower,ou=people,o=sevenSeas cn: Horatio Hornblower $ {noformat} The search finds DN _cn=Horatio Hornblower,ou=people,o=sevenSeas_ for user ID _hhornblo_, and so would Apache Tomcat. In the next step, Tomcat would use this DN to bind against ApacheDS with the given password. If this is successful, the user is authenticated. h4. Authorization With this configuration, roles will be determined by Tomcat with a group search. The following parameters of the _JNDIRealm_ configuration above govern this second search: || Parameter || Value in example || Comments || |roleBase|ou=groups|Search base. Combined with the connection parameter, this leads to "ou=groups,o=sevenSeas"| |roleName|cn|attribute within group entries which carries the role name| |roleSearch|(&(objectClass=groupOfNames)(member=\{0\}))|Search filter. Use '&' instead of '&' due to XML. '\{0\}' will be replaced by Tomcat with the DN of the authenticated user | |roleSubtree|true|Search the whole subtree | Again you can perform the corresponding search with an arbitrary LDAP client. It demonstrates how Tomcat will determine the roles for a given user. This is how it looks with a command line tool for user _hhornblo_ (DN _cn=Horatio Hornblower,ou=people,o=sevenSeas_): {noformat} $ ldapsearch -h zanzibar -p 10389 -b "ou=groups,o=sevenSeas" -s sub \\ "(&(objectClass=groupOfNames)(member=cn=Horatio Hornblower,ou=people,o=sevenSeas))" cn version: 1 version: 1 dn: cn=HMS Lydia,ou=crews,ou=groups,o=sevenSeas cn: HMS Lydia dn: cn=manager,ou=tomcat,ou=groups,o=sevenSeas cn: manager $ {noformat} The search finds two groups for user _hhornblo_, one of them is the _manager_ group created for Tomcat. So _hhornblo_ should be able to log on to Tomcat and work with this application. Let's try it out! h3. Verification After modification of the Tomcat configuration (_server.xml_), you have to restart Tomcat. Check if it starts up successfully. Point with a web browser to the server. A default Tomcat presents a welcome page, if you use the URL _http://:8080/_. !firefox_enter_url.png! If you click to _Tomcat Manager_ (in the _Administration_ box on the left of the welcome screen), or type _http://:8080/manager/html/_ as URL, the authentication dialog of the browser shows up (at least it should). !firefox_basic_auth.png! Enter _hhornblo_ as user name and the password (default in the sample data is "pass"). Press _OK_. If everything works, Tomcat should perform authentication and authorization as described above, and present the Manager web application: !firefox_tomcat_webapp_manager.png! If it does not work (status code 403, for instance), check the log files of Apache Tomcat. Performing the LDAP searches as described above may help to find the problem. h3. Other configuration scenarios The configuration above is just _one_ simple example. In your environment, it may not be appropriate. For instance * Communication between Apache Tomcat and ApacheDS should take place via SSL (LDAPS) * Anonymous access is not allowed * Authentication should take place differently (with a compare operation instead of a simple bind, for instance) * Authorization should be handled differently (with the help of a multiple role attribute for user entries, for instance) * ... Learn more about the configuration options of Apache Tomcat's JNDIRealm in the [Realm Configuration HOW-TO|http://tomcat.apache.org/tomcat-6.0-doc/realm-howto.html|tomcat.apache.org]. h3. Resources * [Apache Tomcat|http://tomcat.apache.org|tomcat.apache.org] Homepage * The Apache Tomcat [Realm Configuration HOW-TO|http://tomcat.apache.org/tomcat-6.0-doc/realm-howto.html|tomcat.apache.org] conatins all configuration options for the _JNDIRealm_ used here * [The Java EE 5 Tutorial|http://java.sun.com/javaee/5/docs/tutorial/doc/|java.sun.com] is written with Sun Java System Application Server in mind. But it includes very helpful information on how to secure Java web applications