Apache, LDAP Authentication, and Active Directory

Recently I’ve been working on moving a common web application hosted in a LAMP stack from an Ubuntu box I’d like to retire to CentOS box.  The outgoing server has Apache 2.2 configured for LDAP authentication with an LDAP filter to limit access to a particular group in Active Directory.  That configuration amounted to only a few lines in an Apache configuration file.  Moving it over to the new server should have been simple, but I ran into a few snags along the way.  These details may be an interesting point of clarification an element of the documentation.

First, while trying to configure the same authentication and authorization pieces on the new server, I was running into issues with the LDAP authorization phase not working when using the DN for the root of the domain.  Next, I was having challenges with the authorization phase for anything more than “Require valid-user” once the authentication phase issue was resolved.

The Search Base

For starters, our AD users who need access to the application are in different OUs that don’t share a common parent object other than the root of the domain.  For reasons that I don’t understand yet, when I use the DN for the root of the domain in the AuthLDAPURL I would have problems in the authentication phase.  I could see this changing my LDAP URL to ldap:// instead of ldaps:// so I could watch the traffic with WireShark on the domain controller.

After the initial ldap bind with the credentials used in AuthLDAPBindDN and AuthLDAPBindPassword there’s a ‘searchResEntry’ for the DN of the user logging in. Next are three successful bind requests followed by ‘wholeSubtree’ search requests for ‘CN=Configuration’, ‘DC=DomainDnsZones’, ‘DC=ForestDnsZones’ DNs.  Three operationErrors with a comment of, ‘In order to perform this operation a successful bind must be completed on the connection’ follow the search requests.  Finally, I get a 500 error from Apache on the browser.

Again, I’m not sure why this is a problem on the CentOS 6 box this application is being migrated to, and it wasn’t a problem on the Ubuntu box the application is being moved away from.  I have seen similar behavior to this before when using LDAP for authentication on Dovecot.  A simple work around is to change the AuthLDAPURL to use the DN of the OU containing the users needing access instead of the DN for the root of the domain, which leads me to the learning experience I’d like to share.

Using AuthnProviderAlias

The Apache mod_authn_alias was the work around I chose to address using different AuthLDAPURL values for users in different OUs.  This module allows Apache to check multiple sources to authenticate users against.   First, I verified Apache is configured to load the authn_alias_module.  Next, I added a few AuthnProviderAlias blocks to an auth_ldap.conf file I added to the /etc/httpd/conf.d directory.  Each block contained a different AuthLDAPURL for the DN of each OU that contain the users I need to accommodate.

Additionally, this directive will not work inside a VirtualHost definition. There is an indicator for this in the comment section of the module documentation, and Apache will complain about it if you put an AuthnProviderAlias block in a VirtualHost definition.

Example:

<AuthnProviderAlias ldap ldap-Company>
AuthLDAPURL "ldaps://dc01.corp.example.com/OU=Company,DC=corp,DC=example,DC=com?sAMAccountName?sub?(objectClass=user)"
AuthLDAPBindDN "srvcldap@corp.example.com"
AuthLDAPBindPassword "somePassword"
</AuthnProviderAlias>

authn vs. authz

With the issue of using multiple LDAP search bases in my directory taken care of for the authentication phase, I was then running into an issue with the authorization phase not working.  Neither a ‘require ldap-group’ or ‘require ldap-filter’ directives would work.  However, a ‘require valid-user’ directive did work.

First I turned up the LogLevel in Apache to debug so I could watch for ldap errors.  With debug turned on  I was seeing the following in the Apache error log:

[error] [client 10.10.67.6] access to / failed, reason: require directives present and no Authoritative handler.

Next, I went back to WireShark to watch the ldap traffic on the domain controller.  In WireShark I wouldn’t see any sort of comparison query in the ldap traffic when using either of the ‘require ldap-*’ directives set in Apache.  Yet, if I used the ‘require valid-user’ directive, I would see a comparison query for the DN of the user being authenticated.

Ultimately, this post to the Apache mail lists led me to the solution after fighting with this problem for several hours. Also, this Stack Overflow post helps clarify the root of the issue.

They key point here is in the difference between authn and authz elements of Apache modules.  The documentation for the mod_authn_alias modules says, “This directive has no affect on authorization, even for modules that provide both authentication and authorization.”  Essentially, Apache didn’t have any information for making an authorization comparison via ldap when using either of the ‘require ldap-*’ directives with the AuthnProverAlias blocks added to the configuration and only specifying those aliases in the AuthBasicProvider directive for the directory  block.

The Solution

The problem was solved by adding AuthLDAPURL, AuthLDAPBindDN, and AuthLDAPBindPassword directives to the directory block to specify how the ldap module should make an ldap comparison for the authorization phase (authz).

Example:

<DirectoryMatch (/usr/lib/nagios/cgi-bin/|/usr/share/nagios/html)>
AuthName "Enter Company Domain User Name: (first.last)"
AuthType Basic
# AuthnProverAlias for different OUs
AuthBasicProvider ldap-Company ldap-OtherCompany ldap-ServiceAccounts
# Values needed for authz component of mod_authnz_ldap module
# Otherwise, authorization phase will fail if these are missing
AuthLDAPURL "ldaps://dc01.corp.example.com/OU=ServiceAccounts,DC=corp,DC=example,DC=com?sAMAccountName?sub"
AuthLDAPBindDN "srvcldap01@corp.example.com"
AuthLDAPBindPassword "somePassword"
Require ldap-group CN=Nagios_Web_Access,OU=ServiceAccounts,DC=corp,DC=example,DC=com
# Require valid-user
</DirectoryMatch>

Some other potentially helpful links:

 

Customizing the AD FS 3.0 Sign-in Page Logo

One of my recent projects was to customize the appearance of the Active Directory Federation Services (AD FS) 3.0 sign-in page to give it a look specific to the company associated with the user who’s logging in.  This article describes how I was able to dynamically customize the AD FS 3.0 sign-in page logo to provide a company specific logo and help text on our AD FS sign-in page based on the domain part of the UPN when logging into AD FS to access Office 365 resources using a federated domain. Continue reading “Customizing the AD FS 3.0 Sign-in Page Logo”

Postfix Kerberos Authentication with Active Directory

This post is meant to be my build doc for configuring the Postfix smtpd to authenticate smtp clients using Cyrus SASL with the Kerberos (GSSAPI) mechanism against Active Directory on a CentOS 6 installation using packages from the distribution. I’m not an expert on this subject. This is from my experience using a lot of reading, trial, and error to get the necessary parts working together.

Continue reading “Postfix Kerberos Authentication with Active Directory”