LDAP(S) Authentication to Active Directory from Apache

This document is to help those who run into the same problem as I have over and over again. Every time I install and configure a new server with Apache, I have trouble setting up LDAP authentication to Active Directory. I think I finally have enough documented sources of what is needed to make this work every time.

The biggest problem I would run into was that I tried to make my LDAP calls work over normal LDAP (TCP port 389) for initial testing and I prefer to bind to the root of the tree instead of a particular OU. This causes problems because Active Directory usually responds to requests by referring you to another Domain Controller (referral chasing). Apache does not support referral chasing when making simple, plain text queries. However, if you bind to a particular OU, your LDAP query will work because you’re telling it the exact location of the user. But this is lacking because it would then require you to have all of your users in the same OU.

The following simple query will function, it says to search a particular OU for users:
AuthLDAPURL “ldap://domaincontroller.domain.com/ou=User Tree,dc=domain,dc=com?cn?sub?(objectClass=user)”

The following simple query will fail because AD will redirect Apache to another DC (which Apache will not do):
AuthLDAPURL “ldap://domaincontroller.domain.com/dc=domain,dc=com?cn?sub?(objectClass=user)”

The following is some additional information on LDAP queries and referral chasing, taken from this document: LDAP and OpenLDAP (on the Linux Platform)

Page 51
The processes of establishing a connection to an LDAP server is referred to as binding. The LDAP protocol level (two or three) and the authentication method used combine to form a bind type. Depending upon the bind type various features of LDAP may or may not be available. For example: plain binds cannot automatically chase referrals, where as binds made by certain SASL methods (GSSAPI) may be able to. The process of binding also determines the level of access based upon access control lists defined on the LDAP server. A connection that specifies no authentication is referred to as an anonymous bind.

Page 52
Depending on how and LDAP server is configured, and with what libraries it was compiled, it may support various authentication methods. You can query a ldap server for the authentication methods it supports using the following command:

$ ldapsearch -H ldaps://localhost/ -x -b “” -s base ” -LLL supportedSASLMechanisms

supportedSASLMechanisms: PLAIN
supportedSASLMechanisms: LOGIN
supportedSASLMechanisms: GSSAPI

Clients that use PLAIN bind cannot automatically chase referrals

Page 96
By default the OpenLDAP utilities do not chase referrals. The OpenLDAP libraries do not support referral and rebind when the client has perfomed a simple bind. This is due to serious security concerns as a simple bind presents the server with a plain text password. Automatic referral of simply bound connections would simply make it much too easy for a rogue server to harvest passwords.

I have also found information that show how to make a simple query work by querying the Global Catalog instead of a normal LDAP query to a particular Domain Controller.

Using the LDAP moniker instructs the query to perform a search using a full replica of the Active Directory database in a domain and, depending on the query, possibly all subdomains. In contrast, using the GC moniker instructs the query to search a global catalog server, which contains a partial replica of its domain and all of its child domains. Consequently, if you query a global catalog server in the root domain, the query contains data from all domains in the forest. Therefore, if all attributes that you want to query are contained in the global catalog, it is more efficient to query this data source than to search one or more full replicas of the Active Directory database in the forest. Source.

To do this, you could make a query like this:
AuthLDAPURL “ldap://domaincontroller.domain.com:3268/dc=domain,dc=com?cn?sub?(objectClass=user)”

My initial discovery of being able to do it was found in this mail archive. The entry also made the statement “Port 3268 is the global catalog which doesen’t return references.” This is all good and now LDAP queries are working without having to search a specific OU, but it’s not secure. And by making it secure, Apache will also support referral chasing.

To do this, we need to change this simple query (that won’t work):
AuthLDAPURL “ldap://domaincontroller.domain.com/dc=domain,dc=com?cn?sub?(objectClass=user)”

Into this secure query:
AuthLDAPURL “ldaps://domaincontroller.domain.com/dc=domain,dc=com?cn?sub?(objectClass=user)”

In order to do this, Apache must trust the certificate that the Domain Controller has installed. This will be the case if the server has a self-signed certificate, a certificate from an internal CA or a certificate from a trusted third-party. In order to do this, you can either tell Apache to trust that one certificate or import that certificate into the root store that already exists when Apache was installed. I usually add it to my ca-bundle file so I only need to maintain one file. Then make sure your httpd.conf file points to that file:

LDAPTrustedCA /etc/apache2/ssl.crt/ca-bundle.crt

It’s important to get the right certificate into that file, but once you have that, you’ll be able to make secure connections to AD and referral chasing will not be a problem. Normally, for Apache, I believe that the certs need to be in Base64 or PEM format. In order to import the certificate, you will need to download the certificate to your server and convert it. This can be down with the following command:

openssl x509 -in yourcert.der -inform der -out output.crt -outform pem -text

Then append it to your ca-bundle.crt file:
cat output.crt >> ca-bundle.crt

I would suggest adding the “-text” option to the command (as above) to get the extra output. I have had problems with Apache reading the certificate properly if I just imported the straight Base64 certificate or if I converted to PEM (Base64) without the “-text” option.

Now that you have LDAPS working, depending on what attributes you really need to search for, it may be benificial to make a secure connection to the Global Catalog server instead. This is more efficient and referral chasing does not take place. In order to do this, you just need to modify your LDAPS query to connect to port 3269 instead of the default LDAP port of 636.

AuthLDAPURL “ldaps://domaincontroller.domain.com:3269/dc=domain,dc=com?cn?sub?(objectClass=user)”

A decent guide to setting up LDAP to communicate to AD over SSL. Not Apache specific.

Hopefully this helps, because everytime I search for this problem, there are a ton of other people searching for this problem, but I almost never find a post for anyone who resolves the problem. Except for this Google Groups post, which happens to be the first post with a resolution that I’ve found. The poster discusses his problem and his resolution, at least making his simple queries work by querying the Global Catalog.