Skip to content

Tomcat Deployment with LDAP

gschueler edited this page Oct 31, 2012 · 1 revision

Note: work in progress

Unfortunately the built-in java LDAPLoginModule doesn't provide a way to get any user Roles from the database, which means we have to implement or adapt the Jetty login module we have for LDAP. This howto describes using the built-in LDAPLoginModule, but will at a later date replace that with the custom one, or use them combined as described below.

Tomcat JAAS and Rundeck

This document describes how to set up Rundeck in Tomcat, using both LDAP and a local file authentication mechanism.

The goals is to allow a local file to define a set of user/passwords for fallback, and a LDAP authentication mechanism for primary user authentication.

There are several ways of doing this:

  1. Define multiple Realms for the application context, such as a JNDIRealm for the ldap authentication, and another custom realm for File based authentication, using tomcat's CombinedRealm. CombinedRealm will succeed if any of the other Realms return a success for login.
  2. Use a JAASRealm and multiple JAAS login module entries in the jaas.conf file, and configure the REQUIRED/SUFFICIENT, etc options. If necessary define custom LoginModule definitions to perform the authentication and/or authorization.
  3. Or define a Tomcat CombinedRealm that incorporates more than one JAASRealms, with or without multiple JAAS Login Module definitions.

This example focuses on item #1 to demonstrate the use of tomcat's built-in file based auth as well as JAAS for the LDAP mechanism.

Define Context Realm

Tomcat uses "Realms" for defining the authentication for web applications. At the top-level you can define a Realm in the conf/server.xml file, and that will apply to all web applications in the server. If you want to define a realm for a specific web application, you will do it within a <Context> definition, which will override any top-level realm defined.

The recommended way is to not define it in the server.xml, so that if necessary you can modify it and reload your web application without restarting tomcat.

Refer to Defining a Context. A simple example is to create /META-INF/context.xml under the expanded war contents directory.

Here is the Context for the Rundeck app, which uses a CombinedRealm to add a UserDatabaseRealm and a JAASRealm. The "UserDatabase" resource must also be defined. (The default tomcat server.xml contains a basic example of the UserDatabaseRealm and UserDatabase definition that you can use.)

<Context>
  <Realm className="org.apache.catalina.realm.CombinedRealm">
      <!-- UserDatabase resource defined earlier -->
      <Realm className="org.apache.catalina.realm.UserDatabaseRealm"
                 resourceName="UserDatabase"/>
  
      <Realm className="org.apache.catalina.realm.JAASRealm"
          appName="myJaasApp"
          userClassNames="com.sun.security.auth.UserPrincipal"
          roleClassNames="com.mycompany.MyRole"
      >

  </Realm>
</Context>

Use the appName attribute to indicate which JAAS configuration to use within your jaas.conf file.

Define jaas.conf for the multiple login module(s).

We define a LdapLoginModule. This module is provided by JAAS. We use REQUIRED option to indicate it must succeed otherwise login will fail.

This module provides authentication but does not provide a set of user roles for authorization.

We need to define a new custom LoginModule to provide Authorization. This is the developer's guide for defining custom login modules.

We can adapt the LDAP code from Jetty's (LdapLoginModule.java)[http://jetty.codehaus.org/jetty/jetty-6/xref/org/mortbay/jetty/plus/jaas/ldap/LdapLoginModule.html] or from the modification included in rundeck the JettyCachingLdapLoginModule. This code uses some Jetty-specific classes for the Principals that must be returned, but the LDAP mechanisms can be reused.

Our new module must add a Principal to the Subject for each role the user belongs to from within the commit() method, of the classname we defined in the JAASRealm ("com.mycompany.MyRole").

Finally, because we want the first module to verify authentication, but the second module to retrieve authorization information, we may or may not need the user's password to retrieve this information. If you do, then we can configure the first LdapLoginModule to have "storePass" option, which stores the username and password for use by the next login module. Our custom login module should check for this information within the shared options for the login module when it comes time to bind to LDAP.

Here is how the jaas.conf file could look:

 myJaasApp {
     com.sun.security.auth.module.LdapLoginModule REQUIRED
     storePass="true"
     ...
     ;
    com.mycompany.MyLdapAuthorizationLoginModule REQUIRED
     
     ...
     ;
 };

The first LdapLoginModule configuration properties should be specified with appropriate authentication information, see the configuration instructions.

define jaas.config location for tomcat

CATALINA_OPTS="-Djava.security.auth.login.config=$CATALINA_HOME/conf/jaas.config"

start the tomcat server.