Search |
|||||||
Tomcat and OpenLDAP, from Configuration to Application
Tue, 2005-05-31
|
|||||||
If the server issues an error and fails to start, check that the
schema entries (above) have been added to the slapd.conf file.
Also, if OpenLDAP was not installed in its default location, verify
that the paths are correct for this location. Once the server is
running, we can verify the installation. Open another command
prompt and issue the command ldapsearch -x -b
"dc=mycompany,dc=com" "(objectclass=*)". The return should
look much like Figure 2.
To populate the directory, a LDIF file will be imported into it.
The format is very unforgiving, so there is an LDIF file available for
download. To import the file, use a command prompt to execute
ldapadd -x -D "cn=Manager,dc=mycompany,dc=com" -W -f
setup.ldif and you should be prompted for your password, as
configured in the slapd.conf file. Once the password
is entered, the results should be as they are in Figure 3.
That was all very nice, but what did these actions accomplish?
Well, basically ldapadd added two organizational
units (people and roles), three user roles (under the roles OU) and
three users (under the people OU). These users were also assigned
to different roles. The hierarchy that is created by importing the
LDIF import follows:
You can now issue another ldapsearch -x -b
"dc=mycompany,dc=com" "(objectclass=*)", and this time the
output should contain something more meaningful (like user attributes and
role memberships), as in Figure 4. While all of this command-line typing
is adequate, a rather good open source Java Swing LDAP browser
named JXplorer can help.
|
|
JXplorer is a LDAP browser. It can be used to view, add, change, and delete any of the elements or attributes in the directory. It can even be used to change passwords, if necessary. Install JXplorer and run jxplorer.bat or jxplorer.sh, depending upon your operating system. Once it's running, connect to your local OpenLDAP directory using your root user and password, as shown in Figure 5.

Figure 5. JXplorer connection screen
JXplorer can be used to browse the directory and change any values. Be careful when changing anything but user attributes (email, password, etc.) until you are comfortable with LDAP. See Figure 6 for an example.
|
|
The Servlet Specification v2.3 allows an application server to
use container-managed security to connect to an existing
user repository for the purposes of authentication and
authorization. There is not, however, a standard way to
accomplish this among different containers. Each container can
(and usually does) implement this in different way. The Tomcat
container uses the notion of a Realm for this type of
security. A Realm can be described as a "repository"
of user names and passwords that uniquely identifies valid users of
a web application. There are four realm types in the Tomcat 4
container and each type stores and retrieves user data and passwords
in a different type of repository.
JDBCRealm uses a relational database.DataSourceRealm uses a relational database via a
JNDI connection.JNDIRealm uses a JNDI connection, usually a LDAP
directory.MemoryRealm uses an in-memory file, usually
tomcat-users.xml.Tomcat's default Realm is a
MemoryRealm, which is configured via the
tomcat-users.xml file. Tomcat needs to be configured for a
JNDIRealm to allow authentication via a LDAP
directory.
There are several steps needed to configure Tomcat to use the
JNDIRealm.
<security-constraint>s to protect
resources in the web.xml file.<login-config> to use the login
form in the web.xml file.<security-role> mappings in
the web.xml file.Each application can have the Realm set up inside
of its respective <Context> element; the realm
is available only to that application. However, the realm
can also be set up at the <Engine> or
<Host> levels. Each of these has an impact on
the behavior, or scope, of the realm. This allows easy sharing of a
single realm over several applications.
Here is a server.xml realm that will allow an application to connect to OpenLDAP.
<Realm className="org.apache.catalina.realm.JNDIRealm"
debug="99"
connectionName="cn=Manager,dc=mycompany,dc=com"
connectionPassword="secret"
connectionURL="ldap://localhost:389"
roleBase="ou=roles,dc=mycompany,dc=com"
roleName="cn"
roleSearch="(uniqueMember={0})"
roleSubtree="false"
userSearch="(uid={0})"
userPassword="userPassword"
userPattern="uid={0},ou=people,dc=mycompany,dc=com"
/>
The userSearch and userPattern
attribute values are the main sources of confusion and errors when
configuring LDAP declaratively. Pay particular attention to these
attributes if you are using anything other than OpenLDAP.
To complete the OpenLDAP configuration for Tomcat, the application's web.xml file must be updated. The application available for download consists of six JSP pages, three of which are protected for the various roles set up in the LDAP directory. The application must be configured to allow form-based authentication and the application must be told what roles exist. First, create a login.jsp file. When using form-based authentication, this JSP must contain the following.
<body>
<form method="POST" action="j_security_check">
<input type="text" name="j_username">
<br>
<input type="password" name="j_password">
<br>
<input type="submit">
</form>
</body>
The web.xml file needs to be updated to reference the new OpenLDAP realm and to use the roles designated by it. The application needs to allow public access to the login.jsp page; otherwise, no user could ever log in.
To inform the application which resources these roles are
allowed to access, URL mappings in the application (or security
constraints) are used. These mappings can be either a file name
(/admin.jsp) or a path (/jsp/* will protect everything
in the jsp folder). The following XML indicates that both of the
listed .jsp files are not to be protected.
<security-constraint>
<web-resource-collection>
<web-resource-name>Public Area</web-resource-name>
<!-- Define the context-relative URL(s) to be protected -->
<url-pattern>/index.jsp</url-pattern>
<url-pattern>/login.jsp</url-pattern>
</web-resource-collection>
</security-constraint>
Why does this code mark the .jsps as unprotected? This is due to
something that is missing, rather than something that is present.
The web.xml snippet below shows that the
user.jsp resource is protected, and which roles can
access it.
<security-constraint>
<web-resource-collection>
<web-resource-name>Protected Area</web-resource-name>
<!-- Define the context-relative URL(s) to be protected -->
<url-pattern>/user.jsp</url-pattern>
</web-resource-collection>
<auth-constraint>
<!-- Anyone with one of the listed roles may access this area -->
<role-name>Test Users</role-name>
<role-name>Special Users</role-name>
<role-name>Admin Users</role-name>
</auth-constraint>
</security-constraint>
Notice that the protected resource has another section,
<auth-constraint>, that specifies which
application roles can access the resource. If an
<auth-constraint> is present, then the
resource(s) are secured. If not, they are public. Unless the entire
application is protected (i.e.,
<url-pattern>/</url-pattern>), the public
security constraint is redundant.
To configure the web.xml file to utilize the login.jsp created earlier, add the following to the web.xml file.
<!-- uses form-based authentication -->
<login-config>
<auth-method>FORM</auth-method>
<form-login-config>
<form-login-page>/login.jsp</form-login-page>
<form-error-page>/fail_login.html</form-error-page>
</form-login-config>
</login-config>
There is one additional step left to make in web.xml: the application needs to be informed of the roles that we are using.
<!-- Security roles referenced by this web application -->
<security-role>
<role-name>Test Users</role-name>
</security-role>
<security-role>
<role-name>Special Users</role-name>
</security-role>
<security-role>
<role-name>Admin Users</role-name>
</security-role>
Tomcat has now been configured to use OpenLDAP and our
application has been set up correctly in the web.xml file. The
first time a user navigates to a resource listed in any
<security-constraint> (other than public
resources) ,the server will automatically display the login.jsp for
the user to authenticate. If the user fails to authenticate
successfully, the page specified in the
<form-error-page> will be displayed. Should a
user be successfully authenticated, but is not authorized
for access to the resource (due to a lack of role membership, for
example), the server returns a 403 error page. Error
pages can be customized if so desired in the web.xml file, using
the <error-code> element.
Note that, the web.xml has a specific order for the
elements (defined by a DTD), so you should take a look at the
complete web.xml available in the sample code (in the
Resources section below). This is
especially true of the <login-config> and
<security-role> sections.
A user can now log in, but what about a user logging out? Code
could be written to invalidate the users' session, or we could use
the handy session taglib supplied by the Apache
Jakarta people.
By adding a logout.jsp to the application and using the
session taglib for the Apache Jakarta Project, we can
invalidate our user without the need from any custom code (in a
real-world application, you may need to do some further clean up of
the user's session, so this may not suffice).
<body>
<sess:invalidate/>
You are now logged out<br>
<a href="index.jsp">Return to index</a>
</body>
Once the JSP page with the <sess:invalidate/>
tag is displayed, the user session is removed and the user is
effectively logged out. Simply putting a link to the
logout.jsp page, and having a user navigate to it, is sufficient
for this simple application. In addition to the session taglib, we
can also utilize the request taglib to customize the content of the
JSP based on the user role or roles.
<req:isUserInRole role="Admin Users">
The remote user is in role "Admin Users".<br />
</req:isUserInRole>
The preceding JSP snippet will only display if the user is in the required role. To verify the behavior of the role security, JXplorer can be used to quickly add and remove users from roles.
Having a LDAP directory available on a local workstation can be a valuable resource for a developer. No more asking the network administrators for access, or more likely, to create test accounts for you. All of these tasks can be done in seconds instead of days or weeks. That isn't to say LDAP is simple. It isn't; it is a powerful and complex system. But with a little know-how and the right tools, it is fairly straightforward to set up.
Thanks to the cross-platform nature of both Tomcat and OpenLDAP, the continuous build servers, CruiseControl, Anthill, etc., can be kept completely separate from any production systems. This type of decoupling has advantages for all.
Worth noting is the fact that all LDAP servers are not equal.
For instance, OpenLDAP does not support the memberOf
attribute for role membership checking, which can be very
irritating at times. The OpenLDAP realm for Tomcat will not
necessarily work if you change Directory servers and the associated
values. That is probably the single biggest challenge when using
LDAP, but by using ldapsearch you can eventually figure
out the values needed.
|
|