Apache and ldap authentication

2007-01-08 5-minute read

The project at hand: Setup an LDAP directory that will work with Apache2 using basic auth. In other words, I want to protect Apache directories by forcing users to enter a username/password (using http basic auth) and have the username and password checked against an ldap server.

This has taken me a week and many many hours, but is finally up and running.

I’m running Debian Etch and started with:

apt-get install slapd

I took all default options and, when prompted, entered:

office.example.org

As my domain

And:

Example Organization

As the name of the organization.

I also entered the password for the admin user.

Without doing anything else, I then tested the setup by running:

ldapsearch -x

The -x means use simple authentication. If you don’t specify -x you’ll be prompted for a SASL password. If you do specify it, you won’t be prompted for a password at all - instead you’ll be logged in automatically as an anonymous user.

On debian, by default, the anonymous user has read access.

My first problem was that after doing this very basic step, I got the following error:

No such object(32)

I spent hours googling around before I found the problem: I didn’t specify the “base dn” to search.

The solution to this problem is to either add the base search dn to your ldapsearch command with -b “cn=admin,dc=office,dc=example,dc=org”

ldapsearch -x -b “cn=admin,dc=office,dc=example,dc=org”

or, better yet, to add the following to /etc/ldap/ldap.conf:

HOST 127.0.0.1 BASE dc=office,dc=example,dc=org

That file is read every time you run ldap.

Next, I wanted to add some information to ldap. This step required some new conceptual understanding that I was lacking. Coming from a sql background, I had to do some translation just to understand what was going on.

One way of thinking about ldap is that you have to first create your container (loosely like creating tables) before you can create objects in those containers. I chose to create an “organizational unit” called People - so that I could add all my users in this organizational unit, allowing me to create other units (like computers, etc.) if I wanted to.

First I created that organizational unit by creating a file called: create-people-ou.ldif with the following contents:

# Setting up container for Users OU
dn: ou=People,dc=office,dc=example,dc=org
objectclass: top
objectclass: organizationalUnit
ou: People

I added this definition to the ldap server with the command:

ldapadd -x -W -D “cn=admin,dc=office,dc=example,dc=org” < create-people-ou.ldif

The -x, as you recall, means use simple authenticatin. The -W means prompt for a password. The -D means bind using the following dn. The argument following is the dn that represents the admin users that the debian install script gave full write access to. Then, you redirect the file you created into standard in and, after being prompted for and entering the password you created via the debian installation, you should be in business.

Check with:

ldapsearch -x

Then, I populated my ldap server with a single record. I created a file called add-user.ldif with the following content:

dn: cn=Jamie McClelland,ou=People,dc=office,dc=example,dc=org
cn: Jamie McClelland
objectClass: shadowAccount
objectClass: inetOrgPerson
givenName: Jamie
sn: McClelland
uid: jmcclelland
mail: jm@not.mayfirst.org
userPassword: {crypt}jfjkle234

The string after {crypt} is the crypted version of the password I want. I’m still trying to figure out how to get md5 to work.

I added this record with:

ldapadd -x -W -D “cn=admin,dc=office,dc=example,dc=org” < add-user.ldif

Again, you can test with:

ldapsearch -x

And you should see this new entry.

If you want to test the password creation (and demonstrate that this new user indeed can authenticate) try:

ldapsearch -x -W -D “cn=Jamie McClelland,dc=office,dc=example,dc=org”

When prompted enter the password you created in your add-user.ldif file.

If it works, you’re in business.

Next, tried to get apache2 to work with ldap. Ldap auth comes with apache2-common, so no new modules needed (another hour wasted to learn this). But you do have to enable it with:

sudo a2enmod authnz_ldap

Next, I added the following to my vhost definition:

AuthzLDAPAuthoritative off
AuthBasicProvider ldap
AuthType Basic
AuthName "Test Jamie"
AuthLDAPURL ldap://localhost/ou=People,dc=office,dc=harlemrbi,dc=org
require valid-user

Well, I didn’t add that at first. I went through the following:

[Mon May 07 13:12:48 2007] [error] Internal error: pcfg_openfile() called with N ULL filename [Mon May 07 13:12:48 2007] [error] [client 192.168.0.150] (9)Bad file descriptor : Could not open password file: (null)

This error will pop up if you leave off:

AuthBasicProvider ldap

With apache 2.2 you have to specify that, or apache will try to use the default file-based basic auth.

Then, I entered the right password via the http basic auth login, no errors in the apache error log, but, rather than getting into my directory, I was presented with the login again. It seemed as though ldap was properly authenticating, however, apache was still not letting me in.

That was because I hadn’t included the line:

AuthzLDAPAuthoritative off

The “require valid-user” uses another auth module. So, I have to say: don’t make ldap authoritative - allow other modules to pitch into this authentication effort.

And finally it is working.

One more note. When troubling shooting ldap, you may want to change the loglevel in your /etc/ldap/slapd.conf file from:

loglevel        0

to

loglevel        any

Then, check syslog for a gazillion log messages.