LDAP Authentication

For the ArsDigita Community System, by Lars Pind on July 1, 2000.
Note, this is still experimental, so it's not part of this release. It'll be rolled in as part of the ACS 4.0 release. If you're interested in helping us test this, please contact me at lars@pinds.com, and I can provide you with the patch.

The Big Picure

Many companies have their own LDAP directory servers where they centrally store information on all the users of their computing equipment, including their user ids and passwords. We want to let users of an ACS-based web site log in using the same user id and password as everywhere else in their computing environment.

Currently, We do not stuff users into the LDAP directory. If a new user is to have access to the site, he must first have an entry created in the LDAP server by some other means.

If you want to know more about what LDAP is, I've actually written up something about it.

The Medium-Sized Picture

An ACS installation is hooked up against one specific, trusted LDAP server. Every user of ACS has to be known to this LDAP server, and the have to live under some agreed-on base DN (e.g. ou=people, dc=arsdigita, dc=com).

This software builds on the assumption that you want all the users under the base DN to have access to this ACS installation. This is not always reasonable, but since we don't deal with authorization, you'll have to modify this yourself. We also assume that you have some other means of maintaining the information in the directory. We don't provide tools for that yet.

The login process goes like this:

  1. We ask for email and password. Since DN's are generally tedious to type, we still rely on emails rather than DN. Since the user might not have a row in the users table, we won't do the old-style "email first, then check if he exists, then ask for password" login process.
  2. We search the LDAP directory for a user with this email address and get back the DN. If there's no such entry, we deny access to the user. If there's more than one, we're in trouble, so we dump an error. If there's exactly one entry, we grab the DN.
  3. We do an LDAP bind operation with the DN just found and the password provided by the user. If it doesn't succeed we complain that the user typed in a bad password.
  4. After the bind, we check to see if we already have a row in the users table with the DN. If we don't, we pull out the person's name from the directory and insert a row.
Important Note: We still have the two special users system and anonymous around. Since their password is still checked against the password in the local database, they pose a security risk. However, they're needed for setting up the site. See the section on installation below for more info.

Under The Hood

LDAP-specifics

The attributes being searched on are
mail: email as typed in by user
objectClass: inetOrgPerson
You might want to add other requirements. How to do that is shown in a comment in LdapLogin.sqlj.

The attributes being retrieved and stuffed into the users table are:

LDAP attributeDescriptionColumn in users table
dn Distinguished name, the primary key of the entry ldap_dn
givenName The person's first name first_names
sn The person's last name (surname) last_name
mail The email address email

Again, you might want to get others. How to do this is shown in LdapLogin.sqlj.

Java API

We don't want to implement an LDAP client in Tcl, so we rely on Sun's JNDI LDAP client in Java 1.2 running inside Oracle.

There are a few Java stored procedures to handle the interfacing between ACS and the LDAP server. Here are their interfaces:

String getDnByEmail(String url, String base, String email) 
String bind(String url, String dn, String password, String securityMechanism) 
String syncUsersTable(String url, String dn)
getDnByEmail
Performs an LDAP search for an inetOrgPerson with a mail attribute that matches the email address given and returns the DN if successful. If there's an error, the string "Error: explanation" is returned.

bind
Performs the LDAP bind operation with the DN and password supplied. It'll use the security mechanism specified in the server parameter file. Returns ok if the bind was successful. If not, it returns Error: explanation

syncUsersTable
If the DN is already in the users table, it simply returns the user_id. If it's not, it queries the LDAP server for the givenName, sn and mail attributes and puts them into the first_names, last_name and email columns of the users table, respectively.

Parameters

There are a few parameters you need to set up, one in the general ACS section, the rest in the LDAP section:
[ns/server/yourdomain/acs]
   ...
; what authentication method we use
; possible values are: internal, ldap
AuthenticationMethod=ldap

   ...

[ns/server/yourdomain/acs/ldap]
; The URL of the LDAP server, including ldap://
ServerURL=ldap://ldap.yourdomain.com
; The base DN under which all the users of this website resides
BaseDN=ou=people,dc=yourdomain,dc=com
; Preferred security mechanisms separated by space, e.g.
; simple, CRAM-MD5, DIGEST-MD5
SecurityMechanism=simple
Important Note: You must make sure you have a login process with email and password prompt on the same page, i.e. the following lines in the general section of your acs .ini file:
; use the old login process where email and password are on separate pages?
SeparateEmailPasswordPagesP=0

Tcl Wrappers

There are straight-forward Tcl wrappers for both the parameters and the Java procs in /packages/acs-core/ldap-procs.tcl.

Patched /www/register Pages

The login process has been modified to accommodate LDAP authentication. The following pages are affected: user-login, user-login-2, deleted-user, restore-user.

Installation

Prerequisites
We assume that you already have the LDAP server running and that you have your directory organization decided i.e., that you know where the users of this website will be stored.
  1. Make sure you have the ldap_dn column in the users table. Here's the DDL to put it in:
    alter table users add (
    	ldap_dn			varchar(400)
    				constraint users_ldap_dn_unq unique
    );
    
  2. Load the Java code
    $ cd /web/yourservice/www/register/java
    $ loadjava -user yourservice/password -resolve -verbose LdapLogin.sqlj
    
    It'll give you a bunch of warnings, but it should compile nevertheless (look out for "source needs recompilation").

  3. Create the JSP wrappers in the database
    $ sqlplus yourservice/password < ldap-authentication-wrappers.sql
    
  4. Set up the parameters, as described above in the parameters section.

  5. Bootstrap yourself as administrator:
    1. Log in as yourself using LDAP authentication, so that you'll have a row in the users table.
    2. Then login as system using the default password (changeme), and make yourself site-wide administrator (visit /admin/ug, group type administration, group site-wide administrators, add member).
    3. Then login as yourself again, and ban the users system and anonymous, so people can't log in as those.

Future Improvements

Obvious enhancements that would improve the usefulness without changing the assumptions are: Bigger things that would change the assumptions:
lars@pinds.com