Authlogic and LDAP Part 1: Authentication
In the Rails, Authlogic and Single Sign On post, we setup a central authentication app to handle user authentication and sessions centrally.
Let’s move on from that…
All our applications are on a closed network which uses Active Directory (AD). Users first authenticate against AD to get to our login page. They again authenticate against our database to get into our application portal. This is cumbersome and impractical because users in most cases have to remember two passwords.
“We don’t mind logging in twice, but why can’t we just use our same credentials?” they cried…
“You can!” we replied.
All our users use their email address and password for AD authentication. We need to configure our application to use the same credentials for application authentication because our application uses a unique username for logging in – not email address.
First, add this line to your environment.rb file (your version may differ):
config.gem "net-ldap", :lib => false, :version => '>=0.0.5'
Modify the UserSession model by telling authlogic to use our own custom method for password verification:
class UserSession < Authlogic::Session::Base verify_password_method :valid_ldap_credentials? end
Next, we need to modify the User model with 3 things:
1. Tell authlogic to use the email field as the username
2. Tell authlogic NOT to validate the password field against the database
3. Implement our custom password verification method
Your User model should look like this:
class User < ActiveRecord::Base
acts_as_authentic do |config|
config.login_field = :email
config.validate_password_field = false
end
protected
def valid_ldap_credentials?(password)
Ldap.valid?(self.username, password)
end
end
Easy enough.
Finally, we create a new class which will talk to AD. The valid? method will return true if the user credentials are valid.
require 'net/ldap'
class Ldap
LDAP_DOMAIN = 'ad'
LDAP_SERVER_IP = '10.193.168.52'
LDAP_USERNAME = 'ldap_username'
LDAP_PASSWORD = 'ldap_password'
def self.valid?(username, password)
init "#{LDAP_DOMAIN}\\#{username}", password
@ldap.bind
end
protected
def self.init(username, password)
@ldap = Net::LDAP.new
@ldap.host = LDAP_SERVER_IP
@ldap.auth username, password
end
end
Finally, you can remove the password fields from your users table using a simple migration.
What about security?
Ah, yes. One very important point is that as we are now validating users against AD by allowing them to enter their AD credentials in a web form, you should use SSL to make sure the details cannot be sniffed and that the form details are encrypted.
In Part 2, we’ll look at how to search for users in the Active Directory.
Trackbacks / Pingbacks