home about

ActiveAuthentication - Active Directory Authentication in Rails

June 18th, 2007 cpetersen

Introduction

In addition to managing our public presence on the web, we spend a considerable amount of time developing internal applications and services. Ruby on Rails makes creating generic webapps a snap; however, for any practical application you need more than just simple CRUD.

How about Authentication?

Most businesses out there, in no small part due to the inflexibility of Windows authentication schemes, reluctantly use Active Directory to manage their user database. Ill conceived parallel authentication schemes that do not fully integrate with AD risk a host of problems: multiple points of failure, more complex security testing, user confusion, complex password management, etc... Instead, wouldn't it be great if your Rails webapp played nice with AD?

Development

To solve these probles, we created ActiveAuthentication. ActiveAuthentication is a Rails plugin that allows users to authenticate against Active Directory

Requirements

  1. Use same username as password as AD account
  2. Transparently manage the creation of new users to your webapp
  3. Respect the suspension/deletion of users from the AD domain

What's Out There

Search first, code second. There are a lot of existing authentication plugins for Ruby on Rails. We didn't want to rewrite what was already working, so after a brief review we elected to build on acts_as_authenticated for our Active Directory authentication system.

Development

With the majority of the work done by others, we made as few modifications as possible. We modified an the Authenticator object by adding and initializing the attributes we need to connect to the Domain Controller. Next we created a new authenticate method. The authenticate method does the following:
  1. Search the database for a user with the same username as the person trying to login.
  2. Connect to the domain controller with the given username and password.
  3. If step 2 failed, reject the login request, otherwise proceed.
  4. Load the user�s information from active directory.
  5. If you found a user in step one, proceed, otherwise create a new user
  6. Populate your user model with the information from Active Directory.
  7. Save the new or updated user.
The actual code is as follows:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
class Authenticator
  connection = nil
  host = nil
  port = nil
  domain = nil
  dn = nil

  def initialization()
    config = YAML::load(File.open("#{RAILS_ROOT}/config/active_directory.yml"))
    @host = config["host"]
    @port = config["port"]
    @domain = config["domain"]
    @dn = config["dn"]
  end

  def authenticate(login, password)
    db_user = <%= class_name %>.find_by_login(login)
    begin
      email = login + "@" + @domain
      connection = LDAP::Conn.new(@host, @port)
      connection.set_option( LDAP::LDAP_OPT_PROTOCOL_VERSION, 3 )
      connection.bind( email, password )
      connection.search( @dn, LDAP::LDAP_SCOPE_SUBTREE, "sAMAccountName=#{login}") do |ad_user|
        if db_user == nil
          db_user = User.new
        end
        db_user.login = login
        db_user.email = email
        db_user.display_name = ad_user.vals("displayName").to_s
        db_user.given_name = ad_user.vals("givenName").to_s
        db_user.last_login_at = Time.new
        db_user.save
      end
      @connection = connection
      db_user
    rescue => e
      puts e
      nil
    end
  end

  def close
    @connection.unbind unless @connection == nil
    @connection = nil
  end
end
If you read the code carefully, you probably noticed the active_directory.yml file that is loaded in the initialization method. This file contains all the information necessary to connect to your domain controller. The file looks like:
1
2
3
4
host: domaincontroller.yourcompany.com
port: 389
domain: yourcompany.com
dn: cn=users,dc=yourcompany,dc=com
Simply replace domaincontroller with the name of your domain controller, and yourcompany with your domain name, and you should be good to go. Depending on how your directory is setup, you may have to experiment with the dn, but this setup worked for us.

Installation

The instructions for using the plugin are the same as they were for the acts_as_authenticated plugin.

Update

You also need to install the ruby ldap libraries. On Ubuntu you can do this with the following command:
sudo apt-get install libldap-ruby1.8
Then you install the plugin:
./script/plugin install http://activeauthentication.googlecode.com/svn/trunk/activeauthentication
Next, generate your user model and update the database:
./script/generate authenticated user account
rake db:migrate
Now include the system in your application.rb file by adding the following code:
include AuthenticatedSystem
Add the before filter to any controllers you want to secure:
before_filter :login_required
Lastly, make sure you edit the active_directory.yml file in the config directory to match your environment. That�s it, now you can forget about administering users in your internal applications.

13 Responses to “ActiveAuthentication - Active Directory Authentication in Rails”

  1. Daniel Says:
    Great! And very easy to use. Just one thing. How can you change the default date format?
  2. Michael Mayo Says:
    This is definitely the best approach I've seen to AD authentication in Rails! I've built a plugin on top of yours to do autocompletes for searching for people, and it's available at: http://code.google.com/p/activedirectorysearch/ It's very alpha, but I hope that it can help you out as much as your plugin has helped me!
  3. overhrd.com &raquo; Blog Archive &raquo; My First Rails Plugin - Active Directory Autocompleter Says:
    [...] Before you install, you’ll need and the activeauthentication plugin. [...]
  4. Christopher L Petersen Says:
    Hi Michael Mayo, That plugin sounds great, I haven't needed that exact functionality yet, so I haven't tried. However, if works as advertised it sounds great. Thanks for the great work! Chris
  5. Christopher L Petersen Says:
    For those of you using Fedora, Geoffrey Gouez has the following advice (Thanks Geoffrey!): For fedora 7 (and maybe core 5 and 6), using activeauthentication throws missing file exception. This files are include in previous version of openssl rpm and are replaced by ***.so.6 For resolve problem, just links files in /lib directory like this : <macro:code> ln /lib/libcrypto.so.6 /lib/libcrypto.so.5 ln /lib/libssl.so.6 /lib/libssl.so.5 </macro:code>
  6. Chap Says:
    This looks great. I haven't been able to get it working yet though. I keep getting the error: "can't convert nil into String". That's as much as it's giving me to diagnose. Anybody have this problem?
  7. Chap Says:
    I figured out my problem. For some reason in active_directory.yml the lines were capitalized. (i.e. "Host:" instead of "host:")
  8. Chap Says:
    New question; does ActiveAuthentication allow for SSL connections? I think that's where I'm getting hung up now.
  9. Eric Says:
    Can I just say: I have tried TONS of plugins/libraries/etc to get Active Directory working with my Rails app, and this is the first one with which I have been successful. Some of that is due to my onw Rails noob-ness, but this plugin made it simple! Thanks a bunch!! :)
  10. Paulo Says:
    Hello I used ActiveAuthentication with my rails application and it works great (for simple login/password authentication). But now I would like to implement a group mechanism (if a user is a member of one group, he can access to a given page, if not, he can't). How can I do this? With ActiveAuthentication it is possible to get the user group information? pjinsc@gmail.com Thanks regards
  11. Ben Says:
    I've just installed ActiveAuthentication. Active Directory seems to be saying the authentication is good (via event viewer) but I am getting an error in my console "Operations Error". Any ideas what this is referring to? I think i have the dn string correct because if i change it, or make the password incorrect I get "invalid credentials". Is there something i'm missing? Thanks ~Ben PS: Is there a mailing list for this plugin? I realise this is not the best place to post issues.
  12. Paulo Says:
    Hello I am using ActiveAuthentication with success. However, I have discovered a problem. In IE, when I am in one page and I make logout, everything works fine. If I click on the "back" button, the login page is displayed. On firefox, when I am on a page, I make a logout, the login page is displayed. But if I click on "back" button I can still access on the application page. It seems that the session as not been closed... Any idea? Thanks regards.
  13. ringtonesNimeaceffiz Says:
    Your site- blog.assaydepot.com is amazing resource, tnks, admin.

Leave a Reply