How to connect Tomcat to AD for Authentication and Authorization, For Development

Overview

The conventional approach when connecting Java Servlets to Active Directory is to use the Java Naming and Directory Interface (JNDI) built into the Web or Servlet Container. This is done by configuring a security realm in the Container, making it available to all servlets inside.

Servlets such as the Tomcat Manager Application, which use the security-restraint mechanism, can immediately take advantage of this interface. Other sevlets can be converted to use container based relatively easily. Configuration of both the Manager App and an example of a servlet with form-based login are detailed below.

Directory Prep

In order for an application to talk to Active Directory, the service must have an account. This is known as a service account. Contact your AD Org Unit Administrator and ask to have a development account and groups created for your system. Alternatively, use your favorite tool and follow the procedure Creating Tomcat Resources in AD, For Development

Tomcat Configuration

Configuring tomcat means editing the server.xml file. This is usually found in [tomcat home]/conf/server.xml, tomcat home being where you installed tomcat at.

server.xml

Tomcat ships with the JNDI resource "UserDatabase" in the server.xml. This is a connection to a flat text file. By substituting our own JNDI resource, we can take advantage of Active Directory.

Note: We use the service account "OIT-tomcat-boss4" in the Org Unit Folder "Ohio/OIT/OIT-SysOps/Service Accounts". Yours will be what your OUAdmin gives you, or what you create.

Comment out:

<!--
      <Realm className="org.apache.catalina.realm.UserDatabaseRealm"
                resourceName="UserDatabase"/>
-->

And then right below it Add

     <Realm className="org.apache.catalina.realm.JNDIRealm"		
		connectionName="CN=jjjjj,OU=Service Accounts,OU=jjjjj"
		connectionPassword="SomePassWord"
		connectionURL="ldap://jjjjj:389"
		userRoleName="member"
		userBase="CN=jjjjj"
		userPattern="CN={0},OU=jjjjjj"
		roleBase="ou=Groups,ou=jjjjj"
		roleName="cn"
        	roleSearch="(member={0})"              
		roleSubtree="false"
         	userSubtree="false"
       />

Note: This is a 'un-encrypted' connection to AD via the LDAP protocol. The problem isn't passwords, they are one-way hashed during the bind process. What is at risk is the data. Who is in what group is passing in plain text. This is in most cases marginally OK. However, if group membership is deemed to be a security risk you can implement LDAPS. (How To Needed)

It is also possible to use MD5 passwords and SASL mechanisms. (How To Needed)

Tomcat Manager

[tomcat home]/webapps/manager/WEB-INF/web.xml

Web App Side Config

The webapp requires a two-part change;

  • a change to your form (if you're reusing your exiting form)
  • an edit to your web.xml.

The Form

To use this with an existing webapp, that has a form (that you don't want to change) simply change the details of your form so it uses the same method, action and names as the following.

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

Tomcat will take these values and pass them to the JNDI module, which will check against Active Directory.

The Web.xml

You add the controls you want by creating rolls and limiting what Resources and Methods that role can access.

If a user is not in the "AD Dev Portal" they will not be able to edit, rename, upload, etc. (see the pages and access listed in the security constraints).

Note that the data constraints are commented out because we have this on the inside network and aren't using SSL. See Section above on SSL implementation.

<!-- This application has two basic areas;                                      -->
<!--    the webroot of the application accessed by all users(/MyWebApp)         -->
<!--    and the admin pages (/MyWebApp/Admin)                                   -->
<!-- We assign the role-name 'Users' to first, and 'Admin' to the second        -->

    <security-constraint>
        <display-name>All Users</display-name>
        <web-resource-collection>
            <web-resource-name>All Users</web-resource-name>
            <url-pattern>/MyWebApp</url-pattern>
        </web-resource-collection>
        <auth-constraint>
            <role-name>Users</role-name>
        </auth-constraint>
    </security-constraint>

    <security-constraint>
        <display-name>Admin Users</display-name>
        <web-resource-collection>
            <web-resource-name>Admin Users</web-resource-name>
            <url-pattern>/MyWebApp/Admin</url-pattern>
        </web-resource-collection>
        <auth-constraint>
            <role-name>Admins</role-name>
        </auth-constraint>
    </security-constraint>


<!-- And here we map the User and Admin roles to the corresponding Active Directory groups -->

    <security-role>
        <description>CBW Webapp Admins</description>
        <role-name>Admin</role-name>
        <group-name>CBW-WebappAdmin</group-name>
    </security-role>

    <security-role>
        <description>CBW Webapp Users</description>
        <role-name>User</role-name>
        <group-name>CBW-WebappUser</group-name>
    </security-role>


<!-- We can also specify how to handle log in -->

   <login-config>
       <auth-method>FORM</auth-method>
           <form-login-config>/MyWebApp/login.jsp</form-login-config>
           <form-error-page>/MyWebApp/error_login.jsp</form-error-page>
   </login-config>

More web.xml

The previous example did not seem to work, but here is another possible configuration. In the web.xml for the application (Tomcat manager, lambda probe, etc), add a security-role for your Active Directory group. Then add references to that role along side any references to other security-roles that came with the application. In this way you extend the original configuration rather than alter it.

For example, within the Tomcat Manager web.xml file:

  <!-- Define a Security Constraint on this Application -->
  <security-constraint>
    <web-resource-collection>
      <web-resource-name>HTMLManger and Manager command</web-resource-name>
      <url-pattern>/jmxproxy/*</url-pattern>
      <url-pattern>/html/*</url-pattern>
      <url-pattern>/list</url-pattern>
      <url-pattern>/expire</url-pattern>
      <url-pattern>/sessions</url-pattern>
      <url-pattern>/start</url-pattern>
      <url-pattern>/stop</url-pattern>
      <url-pattern>/install</url-pattern>
      <url-pattern>/remove</url-pattern>
      <url-pattern>/deploy</url-pattern>
      <url-pattern>/undeploy</url-pattern>
      <url-pattern>/reload</url-pattern>
      <url-pattern>/save</url-pattern>
      <url-pattern>/serverinfo</url-pattern>
      <url-pattern>/status/*</url-pattern>
      <url-pattern>/roles</url-pattern>
      <url-pattern>/resources</url-pattern>
    </web-resource-collection>
    <auth-constraint>
       <!-- NOTE:  This role is not present in the default users file -->
       <!-- Ohio University: Added the OIT-Tomcat-Admin AD group with same privs as a manager. -->
       <role-name>manager</role-name>
       <role-name>OIT-Tomcat-Admin</role-name>
    </auth-constraint>
  </security-constraint>

  <!-- Define the Login Configuration for this Application -->
  <login-config>
    <auth-method>BASIC</auth-method>
    <realm-name>Tomcat Manager Application</realm-name>
  </login-config>

  <!-- Security roles referenced by this web application -->
  <security-role>
    <description>The role that is required to log in to the Manager Application</description>
    <role-name>manager</role-name>
  </security-role>

  <!-- Ohio University: Added the OIT-Tomcat-Admin Active Directory Group. -->
  <security-role>
    <description>Declares an OIT AD Group to the Tomcat Manager Application</description>
    <role-name>OIT-Tomcat-Admin</role-name>
  </security-role>

Notes:

Setting up LDAPS

Adding the AD CA to the keystore that tomcat is configured to use, similar to how we add the Geotrust CA, should do the trick

In the webapp, you can ensure transport security by adding a constraint as below - if - you have setup LDAPS on the server

    <security-constraint>
        <display-name>All Users</display-name>
        <web-resource-collection>
            <web-resource-name>All Users</web-resource-name>
            <url-pattern>/MyWebApp</url-pattern>
        </web-resource-collection>
        <auth-constraint>
            <role-name>Users</role-name>
        </auth-constraint>

        <user-data-constraint>
            <transport-guarantee>CONFIDENTIAL</transport-guarantee>
        </user-data-constraint>

    </security-constraint>
Comments