Wednesday, July 6, 2011

ReviewBoard and Microsoft Acitive Directory Authentication

In an effort to get ReviewBoard 1.6 RC1 to use Microsoft Active Directory for user authentication, an obstacle was encountered.  After changing the authentication method from the default Standard Registration to Active Directory with "Use TLS for authentication" enabled, LDAP+TLS communications resulted in an TLS "Unknown CA" fatal alert message.

Before getting into the LDAP+TLS "Unknown CA" fatal message, here are some relevant environment details.  ReviewBoard was installed on a Ubuntu Lucid 10.04 machine with OpenLDAP 2.4.25 client tools installed.  A test site was created using SQLite for the database backend and Lighttpd for the web server.  Active Directory uses certificates generated by an internal certification authority that uses a self-signed root certificate.  The self-signed CA certificate was saved to the /usr/share/ca-certificates/example.com directory, dpkg-reconfigure ca-certificates was executed, the user's $HOME/.ldaprc file was edited to contain TLS_CACERTDIR /usr/share/ca-certificates/example.com and the following test command completed successfully.

ldapsearch -v -d 1 -H ldaps://msad.example.com/ -x -W -D user@example.com -b DC=example,DC=com '(&(objectClass=user)(userPrincipalName=user@example.com))'

Though running OpenLDAP commands from a terminal succeed, ReviewBoard authentication would fail with a "Incorrect username or password." message.  The following test Python script was used to verify there was no issue with Python and LDAP+SSL or LDAP+TLS:

#!/usr/bin/env python

import ldap, ssl
from M2Crypto import X509

host = 'msad.example.com'
# Missing newline before end tag: http://bugs.python.org/issue8086
pem = ssl.get_server_certificate((host, 636)).replace('-----END CERTIFICATE-----', '\n-----END CERTIFICATE-----')
x509 = X509.load_cert_string(pem)
print x509.as_text()
print pem

l = ldap.initialize('ldap://' + host + ':389')
l.set_option(ldap.OPT_PROTOCOL_VERSION, 3)
l.start_tls_s()
l.simple_bind_s('user@example.com', 'password')
e = l.search_s('DC=example,DC=com', ldap.SCOPE_SUBTREE, '(&(objectClass=user)(sAMAccountName=user*))')
print e
del l

The solution to the LDAP+TLS "Unknown CA" fatal message during ReviewBoard Active Directory authentication turns out to be pretty simple.  After reviewing the $RB_SITE_HOME/htdocs/reviewboard.fcgi file, it was noted that the HOME environment variable is changed to $RB_SITE_HOME/data.  In this directory, add a ldaprc file containing "TLS_CACERTDIR /usr/share/ca-certificates/example.com".  You should now be able to log in using an Active Directory account.  You can still log in with the built-in administrator account created during installation to perform administrative maintenance.