Active Directory on Rails

We have been receiving multiple customer requests for integrating Coupa with Microsoft Active Directory, primarily for Single-Sign On purposes, so we decided it was worth investigating.

Considering Active Directory implements LDAP, which is quite a mature standard, we thought it’d be a piece of cake to implement. In the end it turned out to be very easy, but the whole LDAP association clouded my search abilities, and I ended up spending some time looking at some excellent but pretty low level libraries and tips. Once I used the terms “activedirectory” and “active directory” in my searches, the rest was trivial…

This is all thanks to Justin Mecham’s ActiveDirectory gem. Not only does it wrap ActiveDirectory objects in an ActiveRecord-like interface, more importantly for us, it provides a built-in method for authenticating a user against the directory! So all we had to do was:

ActiveDirectory::User.find(username).authenticate(password)

Even when we thought it’d be a piece of cake, we didn’t think it’d be a one-line piece of cake! Granted there are a bunch of exceptions you have to catch and stuff, but it’s a pretty trivial solution to what could be seen as a pretty advanced feature. I am also going to document the setup required for this piece of magic to work.

First of all, you need to install the underlying Ruby/LDAP package. If you’re running on Windows, you get to install Jan Szumiec’s gem:

gem i http://jps.kni.pk.edu.pl/files/ldap-0.9.7-mswin32.gem --include-dependencies

There’s also a binary distribution in the form of a RPM, but everybody else will have to compile it from source.

Next, we install the activedirectory gem itself:

gem i activedirectory --include-dependencies

And we add the Active Directory settings to the environment.rb:

require_gem 'activedirectory'
ActiveDirectory::Base.server_settings = {
  :host     => "directory.example.com",
  :port     => 389,
  :username => "username",
  :password => "password",
  :domain   => "example.com",
  :base_dn  => "DC=example,DC=com"
}

Those of you are currently using the Login Engine by James Adam can also refer to our extension that authenticates against Active Directory when it is available. If you can’t wait for the Active Directory code to get merged back into trunk, grab the active directory branch:

svn co http://svn.coupa.com/coupa_engine/branches/activedirectory-sso

That’s it, folks!

UPDATE - Running as a service

Just found out that the ActiveDirectory gem creates its own Logger and so when you try to run your new ActiveDirectory-enabled Rails app as a Win32 service, it will fail when the ActiveDirectory module first tries to connect to a directory server! Much hair was lost to bring you this piece of information…..

Do the following in your environment.rb together with the server settings:

ActiveDirectory::Base.logger = RAILS_DEFAULT_LOGGER

and you will be fine. Of course, you could use a different logger if you wish.