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
- Use same username as password as AD account
- Transparently manage the creation of new users to your webapp
- 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:
- Search the database for a user with the same username as the person trying to login.
- Connect to the domain controller with the given username and password.
- If step 2 failed, reject the login request, otherwise proceed.
- Load the user�s information from active directory.
- If you found a user in step one, proceed, otherwise create a new user
- Populate your user model with the information from Active Directory.
- 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.
August 20th, 2007 at 04:13 AM Great! And very easy to use. Just one thing. How can you change the default date format?
September 29th, 2007 at 12:52 PM 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!
September 30th, 2007 at 10:59 PM [...] Before you install, you’ll need and the activeauthentication plugin. [...]
October 6th, 2007 at 09:49 AM 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
October 6th, 2007 at 11:07 AM 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>
February 11th, 2008 at 06:05 AM 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?
February 12th, 2008 at 02:19 AM I figured out my problem. For some reason in active_directory.yml the lines were capitalized. (i.e. "Host:" instead of "host:")
February 12th, 2008 at 04:02 AM New question; does ActiveAuthentication allow for SSL connections? I think that's where I'm getting hung up now.
May 9th, 2008 at 07:47 AM 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!! :)
June 5th, 2008 at 11:45 PM 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
June 9th, 2008 at 10:34 PM 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.
July 10th, 2008 at 01:44 AM 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.
July 29th, 2008 at 01:32 PM Your site- blog.assaydepot.com is amazing resource, tnks, admin.