Skip to content

Instantly share code, notes, and snippets.

@viniciussbs
Forked from boopathi/adauth.rb
Created October 20, 2018 16:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save viniciussbs/40817495d244d0992b034b185d6a8478 to your computer and use it in GitHub Desktop.
Save viniciussbs/40817495d244d0992b034b185d6a8478 to your computer and use it in GitHub Desktop.
Ruby AD Authentication
# 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