Created
October 15, 2012 09:45
-
-
Save boopathi/3891733 to your computer and use it in GitHub Desktop.
Ruby AD Authentication
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Usage: | |
# user = ActiveDirectoryUser.authenticate('boopathi','password') | |
# user.first_name # => "Boopathi" | |
# user.flanderized_first_name # => "Boopathi Rajaa" | |
# user.groups # => ["Mac Users", "Geeks", "Ruby Coders", ... ] | |
require 'net/ldap' # gem install ruby-net-ldap | |
class ActiveDirectoryUser | |
### BEGIN CONFIGURATION ### | |
SERVER = 'ad01.company.com' # Active Directory server name or IP | |
PORT = 389 # Active Directory server port (default 389) | |
BASE = 'DC=company,DC=com' # Base to search from | |
DOMAIN = 'company.com' # For simplified user@domain format login | |
# ATTR_SV is for single valued attributes only. Generated readers will | |
# convert the value to a string before returning or calling your Proc. | |
ATTR_SV = { | |
:login => :samaccountname, | |
:first_name => :givenname, | |
:last_name => :sn, | |
:email => :mail | |
} | |
# ATTR_MV is for multi-valued attributes. Generated readers will always | |
# return an array. | |
ATTR_MV = { | |
:groups => [ :memberof, | |
# Get the simplified name of first-level groups. | |
# TODO: Handle escaped special characters | |
Proc.new {|g| g.sub(/.*?CN=(.*?),.*/, '\1')} ] | |
} | |
# Exposing the raw Net::LDAP::Entry is probably overkill, but could be set | |
# up by uncommenting the line below if you disagree. | |
# attr_reader :entry | |
### END CONFIGURATION ### | |
# Automatically fail login if login or password are empty. Otherwise, try | |
# to initialize a Net::LDAP object and call its bind method. If successful, | |
# we find the LDAP entry for the user and initialize with it. Returns nil | |
# on failure. | |
def self.authenticate(login, pass) | |
return nil if login.empty? or pass.empty? | |
conn = Net::LDAP.new :host => SERVER, | |
:port => PORT, | |
:base => BASE, | |
:auth => { :username => "#{login}@#{DOMAIN}", | |
:password => pass, | |
:method => :simple } | |
if conn.bind and user = conn.search(:filter => "sAMAccountName=#{login}").first | |
return self.new(user) | |
else | |
return nil | |
end | |
# If we don't rescue this, Net::LDAP is decidedly ungraceful about failing | |
# to connect to the server. We'd prefer to say authentication failed. | |
rescue Net::LDAP::LdapError => e | |
return nil | |
end | |
def full_name | |
self.first_name + ' ' + self.last_name | |
end | |
def member_of?(group) | |
self.groups.include?(group) | |
end | |
private | |
def initialize(entry) | |
@entry = entry | |
self.class.class_eval do | |
generate_single_value_readers | |
generate_multi_value_readers | |
end | |
end | |
def self.generate_single_value_readers | |
ATTR_SV.each_pair do |k, v| | |
val, block = Array(v) | |
define_method(k) do | |
if @entry.attribute_names.include?(val) | |
if block.is_a?(Proc) | |
return block[@entry.send(val).to_s] | |
else | |
return @entry.send(val).to_s | |
end | |
else | |
return '' | |
end | |
end | |
end | |
end | |
def self.generate_multi_value_readers | |
ATTR_MV.each_pair do |k, v| | |
val, block = Array(v) | |
define_method(k) do | |
if @entry.attribute_names.include?(val) | |
if block.is_a?(Proc) | |
return @entry.send(val).collect(&block) | |
else | |
return @entry.send(val) | |
end | |
else | |
return [] | |
end | |
end | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment