LDAP and Apache Basic Auth – how it works and how it doesn’t work

Let’s imagine you work on an organization which uses Active Directory (just kidding, is there anyone who doesn’t …?) and on which people are forced to comply with draconian security policies, such as changing you strong password every N days (replace N for any number less than 30… why don’t people understand that it is harder for people to memorize a new strong password, than machines to brake them). Anyways, having a central location for all authentication purposes is, from any point of view, a good idea, even if coming from Microsoft :).

If your organization already has in place an AD (Active Directory) infrastructure, then it is also a goo idea that any new applications to perform it’s authentication on top of it.

Now, most applications are the simplest ones, typically an php or Perl web page which accesses information in a manner thousands of times more effective than doing it manually. However, those ad-hoc solutions usually come with a caveat: poor authentication techniques, usually no access control at all or stand alone passwords. As these applications appear overnight like mushrooms, people easily get literally tens of different logins and passwords.

And we arrive to the solution to this problem: Apache Basic Auth with LDAP.

Apache Basic Auth is based on HTTP 1.0 Basic Auth back in 1996 and extended it to support several sources of authentication, from the basic login/username and groups, to full fledged database user control, including other more advanced methods such as LDAP and RADIUS.

To configure LDAP authentication on Apache, there are two main methods: httpd.conf and .htaccess, which are mostly equivalent. For the purposes of this text, we’ll use .htaccess. Also, you need to take into account how LDAP works, and how Apache 2.2 works with LDAP (there are some changes on Apache 2.4, but those are only important whenever Red Hat supports it…).

On the first place, LDAP is little more than an directory which stores organizational information on people: logins, names, surnames, telephone number, organizations, emails, etc. Now, you can either have this information public, which is a very bad idea, or protecting it making sure that only people present on the directory is able to access it. For this to happen, people need to authenticate themselves, by login and password.

The usual .htaccess configuration is something like this:

AuthName "Restricted access"
AuthType Basic
AuthBasicProvider ldap
AuthLDAPUrl "ldap://ldap_server_address:3268/dc=_example_dc_,dc=_example_dc_,dc=com?sAMAccountName?sub?(objectClass=*)"
AuthLDAPBindDN "_domain_\_generic_login_"
AuthLDAPBindPassword "_the_generic_login_password_"
AuthUserFile /dev/null
Require valid-user

In more layman’s terms it works like this:

  1. AuthType – Use basic Auth
  2. AuthBasicProvider – Use LDAP as auth source. For this to work, mod_ldap must be loaded
  3. AuthLDAPUrl – The URL in LDAP wording of what to search for
  4. AuthLDAPBindDN and AuthLDAPBindPassword – we’ll check this later
  5. AuthUserFile – Is present compares the user to a predefined list of authorized users
  6. Require valid-user – means that any user than sucessfully authenticates on LDAP is authorized to access the resource

Now Apache 2.2 does this on a weird fashion (and maybe outright stupid): first it searches for the login on the directory and then it tries to authenticate it with the password. Now if you LDAP directory only allows for authenticated searches through the directory you’re busted. To get around this, you need to create a dedicated login which Apache can use to browse through the directory looking for users. This is why there are fields named AuthLDAPBindDN and AuthLDAPBindPassword on the .htaccess file. So in here you need to put the login and password Apache will use to browse through the directory. Not exactly a great idea, but it works.

Also, you need to take into account the AD LDAP login format. There are two main LDAP login formats: usual LDAP format, based on DN and CN, and Kerberos ID, also known as _domain_\_login_. The example above uses the latter. Please take this very seriously are they’re not fully interoperable.

Now, you need to take into account browser interoperability. If you make sure that all logins AND passwords are in ASCII format, nothing to see here, move along. However, is either the logins or the passwords can use non ASCII characters things go bad easily. When people defined HTTP basic auth, there was only one charset on the internet: ASCII, so they assumed everyone would only use ASCII. How this is not true today, and for a long time, but the HTTP RFC as never updated to add this characteristic, so people started getting creative. On Microsoft side, Internet Explorer uses the system charset if ASCII is not enough (usually ISO-8859-1). Firefox uses ISO-8859-1. Chome got one stop forward and went to UTF-8, which in paper is the right solution, until people realized it doesn’t work, since ever.

So, if you’re looking for a simple authentication, which can only support ASCII logins and passwords, Apache Basic Auth is the way to go. Otherwise, you’d better invest a couple of extra hours, and do yourself a proper authentication purposes, either through php or perl.