I’ve spent a bit less than a week attempting to configure Apache to work with Active Directory authentication for Trac on Windows 2003 Server. Getting the LDAP syntax correct was an absolute horror and took three times forever. Here I’ve documented my findings.
Final {Apache root}/conf/httpd.conf configuration excerpt:
<Directory /projects/>
#Trac setup for mod_python
SetHandler mod_python
PythonInterpreter main_interpreter
PythonHandler trac.web.modpython_frontend
PythonOption TracEnv C:/Trac/projects/
PythonOption TracUriRoot /projects
#Apache authentication setup
Order allow,deny
Allow from all
AuthType Basic
AuthName "Trac"
AuthBasicProvider ldap
AuthLDAPBindDN "anActiveDirectoryUsername@yourdomainname.com"
AuthLDAPBindPassword passwordForAboveUser
AuthzLDAPAuthoritative Off
AuthLDAPURL "ldap://adservernamehere:3268/DC=domainname,DC=com?sAMAccountName?sub"
require group CN=authorizedGroupNameGoesHere
</Directory>
Notes:
1. The AuthName directive specifies the text that displays on the login dialog in the form “The server at AuthName requires a username and password”
2. The AuthBasicProvider directive determines which Apache module to load. Using “ldap” as shown here requires that the following LoadModule statements be in your httpd.conf:
LoadModule authnz_ldap_module modules/mod_authnz_ldap.so
LoadModule ldap_module modules/mod_ldap.so
3. The AuthLDAPBindDN directive refers to a user account that has read access to the Active Directory tree structure. This account is used by Apache to determine whether the user logging in is valid.
4. The AuthzLDAPAuthoritative directive essentially tells Apache to pass information about the authentication to other Apache modules when set to “On”
5. The Require directive determines which users are considered authorized. The syntax shown here tells Apache to only authorize users who are in the group called “authorizedGroupNameGoesHere”. There are several options for this directive that range from hardcoding authorized usernames to specifying complicated LDAP queries. You can find out more by reading the mod_authnz_ldap documentation.
6. The biggest problem I had was getting the AuthzLDAPURL syntax right. This directive tells Apache how to contact Active Directory and where to look in the tree structure for users. Tip: If you use port 3268 as shown here instead of port 389, your query will be executed against a “flattened” tree structure and therefore is more likely to work – it’s a pisser to get the syntax correct otherwise. Further note that “referrals” or “referral chasing” (I don’t know much about Active Directory, obviously) in your AD tree structure WILL cause problems with the AuthzLDAPURL directive – and there’s no way to turn it off (see Apache Bug 42557). Apparently Apache attempts to reconnect to Active Directory for each referral, but doesn’t reauthenticate using the credentials from the original authentication. My solution was to use a query that excluded tree nodes that were referrals – not intentionally, it just worked out that way.
You will also want to be careful with how specific you are with the AuthzLDAPURL query. In my case
DC=domainname,DC=com
was as specific as I could get before running into referral problems. It was much easier to compose the query after downloading Softerra LDAP Administrator because it showed me in real-time which query arguments caused problems. It includes an option to turn off referral chasing, which was also useful to determine which nodes contained referrals and should therefore be excluded.
Errors
The following errors in {Apache root}/logs/error.log will occur when the account specified by AuthLDAPBindDN does not have permission to read the Active Directory tree structure (most likely the password specified by AuthLDAPBindPassword is wrong or you need to use the Active Directory Distinguished Name for the user):
auth_ldap authenticate: user spork authentication failed; URI /projects/ [LDAP: ldap_simple_bind_s() failed][Invalid Credentials]
user spork: authentication failure for "/projects/": Password Mismatch
The obvious solution is to check the credentials and try again.
The following errors in the error log will occur when the AuthzLDAPURL query is too restrictive to find the user who tried to log in:
auth_ldap authenticate: user spork authentication failed; URI /projects/ [User not found][No Such Object]
auth_ldap authenticate: user spork authentication failed; URI /projects/FieldPlus [ldap_search_ext_s() for user failed][No Such Object]
The solution I found was to change the AuthzLDAPURL query to least restrictive and work towards more specific until it found my user account (using Softerra LDAP Administrator).
The following error in the error log will occur when the AuthzLDAPURL query results in referral chasing:
auth_ldap authenticate: user spork authentication failed; URI /projects/FieldPlus [ldap_search_ext_s() for user failed][Operations Error]
The solution I found was to again change the AuthzLDAPURL query until no more referrals were included.