HomeRamblings  ⁄  SystemsServersSetupsConfiguration

Apache 2.2 and Active Directory and Group restrictions

Published: July 22, 2009 (over 10 years ago)
Updated: over 4 years ago

I was really struggling with getting Apache and Active Directory talking and restricting access (authorizing) only a sub-set of users that belonged to a particular group. Here, I show you how I solved the problem.

The Stage

I am setting up a Ubuntu server with Apache 2.2 and authenticating users against a Windows 2003 Server's Active Directory. This is standard fare when all you need is a require valid-user directive. But when it came to getting require ldap-group directive going, I really stumbled. And on multiple fronts, too. I am not a Windows guru by any measure, nor am I an LDAP guru, so there was a huge cultural and vocabulary barrier for me to cross on both the LDAP vernacular and the somewhat different parlance surrounding Microsoft's documentation on Active Directory. Its like a Southern Redneck talking to a Scottish Highlander about home-brewing beer.

So here's what we're going to do:

  • Apache 2.2
  • Microsoft Active Directory (Windows 2003 Server)
  • authnz_ldap module

For this effort, I am authenticating users that reside in the MyBusiness -> Users folders and I'm restricting access to the Auditors Security Group, also residing under MyBusiness. The domain I use is "sample.local" herein. See the screen shot of the Active Directory structure and details of the Auditors group below:

Active Directory Screenshot

There are plenty of resources out there about getting the authnz_ldap module working with Apache, so I won't be covering this part of the setup. Instead, I will focus on the gestalt of the actual configuration.

Will the Real AuthLdapUrl Please Stand Up?

There seems to be no real standard way to set the AuthLdapURL configuration string. I think I visited ten or fifteen web sites on the topic and each one was a little bit different! And none really explained fully the chosen syntax and LDAP selectors being used. Fortunately, I came across a site dedicated to explaining CSVDE, which turned out to be a bit of a rosetta stone for me.

CSVDE is a tool I had never heard of, but yet is apparently installed on every Windows 2003 Server. After about five minutes of reading and 20 minutes of perusing the CSV export I generated, I knew exactly how to construct the AuthLdapURL configuration string. Well, with one caveat, that is. I still am not sure what "(objectClass=*)" does for me, but several examples had it and I kept it.

Know your Users

All of my users are maintained under group policies and they reside under the domain's root node in "MyBusiness" and "Users" under that. Standard Windows accounts, especially system administrator accounts reside in a "Users" folder directly off the domain's root node. This was one of the first points of contention that I had to understand when looking at the vast majority of other people's solution. Simply put, know which "Users" you wish to work with in Apache.

Knowing I wanted to authenticate users under the MyBusiness node, my AuthLdapUrl becomes:

AuthLDAPURL ldap://ad.sample.local:389/OU=MyBusiness,DC=sample,DC=local?sAMAccountName?sub?(objectClass=*)

Bind a User so Apache can Query

You do have to bind to Active Directory so that Apache can actually query. To do this, I created a User under the standard "Users" folder (where administrator, and other such accounts traditionally reside). I don't know if I applied correct rights or not, but the account is no more than a "Domain User" member. I called the user "AD_VIEWER" with description "Account to bind Apache to Active Directory for authentication." This leads to the following Apache directives:

AuthLDAPBindDN "[email protected]"
AuthLDAPBindPassword bottom_secret_password

I tested the above getting the usual "require valid-user" directive working with Apache. Once I was sure I could do this much, it was time to turn my attention to restricting access to users that are members of a specific group.

Where's my Group?

I struggled for quite a while with the groups before I finally got wise and set the debug level to get more details into the apache log files. The debug logging level can be set with:

LogLevel debug

And this leads to quite detailed information about what's going on with Apache and Authentication. For example, before I got my ldap-group configuration correct, I was seeing this:

[debug] mod_authnz_ldap.c(721): [2934] auth_ldap authorise: require group: testing for uniquemember: CN=Code Connoisseur,OU=MyBusiness,OU=Users,DC=sample,DC=local (CN=Auditors,OU=MyBusiness,DC=sample,DC=local)
[debug] mod_authnz_ldap.c(737): [2934] auth_ldap authorise: require group "CN=Auditors,OU=MyBusiness,DC=sample,DC=local": authorisation failed [Comparison complete][No such object]
[debug] mod_authnz_ldap.c(852): [2934] auth_ldap authorise: authorisation denied

Note the "No such object" as this was telling me the group itself was not found. I tried many permutations without success until I found the CSVDE program and was able to dump the Active Directory to Excel for further inspection. I realized with the CSVDE output that I was doing both the AuthLDAPURL (the above AuthLDAPURL is correct as I have spared you from my mistakes). The correct ldap-group config string for accessing a Security Group defined under MyBusiness is:

require ldap-group CN=Auditors,OU=Security Groups,OU=MyBusiness,DC=sample,DC=local

In short, you have to exactly declare the selector for your Active Directory Group or Apache will fail to find it. After getting the group setting right, I now see "attribute member" and "Comparison true" in the logs, which indicates that the group was found and that my user is a member of that group.

[debug] mod_authnz_ldap.c(377): [3134] auth_ldap authenticate: using URL ldap://,DC=sample,DC=local?sAMAccountName?sub?(objectClass=*)
[debug] mod_authnz_ldap.c(474): [3134] auth_ldap authenticate: accepting mwlang
[debug] mod_authnz_ldap.c(715): [3134] auth_ldap authorise: require group: testing for group membership in "CN=Auditors,OU=Security Groups,OU=MyBusiness,DC=sample,DC=local"
[debug] mod_authnz_ldap.c(721): [3134] auth_ldap authorise: require group: testing for member: CN=Michael Lang,OU=Employees,OU=Users,OU=Users,OU=MyBusiness,DC=sample,DC=local (CN=Auditors,OU=Security Groups,OU=MyBusiness,DC=sample,DC=local)
[debug] mod_authnz_ldap.c(730): [3134] auth_ldap authorise: require group: authorisation successful (attribute member) [Comparison true (adding to cache)][Compare True]

The complete Apache Config

Bringing all of the items discussed above together, we arrive at this Apache configuration. I am using Virtual Hosts to uniquely identify the service. Also of note, I am using Ramaze to provide the functionality of the actual site, so please do take this into account if you're copying and pasting. This config is a complete virtual host entry:

<VirtualHost *:80>
    ServerName audit.sample.local
    RackBaseURI /
    RackAutoDetect on
    DocumentRoot /var/www/balancer/public

    LogLevel debug
    <Location "/data_entry">
        AuthBasicProvider ldap
        AuthType Basic
        AuthName "Sample Realm"
        AuthLDAPURL ldap://,DC=sample,DC=local?sAMAccountName?sub?(objectClass=*)
        AuthzLDAPAuthoritative on

        AuthLDAPBindDN "[email protected]"
        AuthLDAPBindPassword bottom_secret_password

        AuthLDAPGroupAttributeIsDN on
        require ldap-group CN=Auditors,OU=Security Groups,OU=MyBusiness,DC=sample,DC=local

comments powered by Disqus