lib/adauth/ad_object.rb
require "active_support/core_ext/object/try"
module Adauth
# Container for Objects which inherit from Adauth::AdObject
module AdObjects
end
# Add a field to the specified model
def self.add_field(object, adauth_method, ldap_method)
Adauth.logger.info(object.inspect) { "Adding field \"#{ldap_method}\"" }
object::Fields[adauth_method] = ldap_method
end
# Active Directory Interface Object
#
# Objects inherit from this class.
#
# Provides all the common functions for Active Directory.
class AdObject
include Expects
def self.method_missing(method, *args)
return super unless method =~ /^find_by_/
method_field = method.to_s.split("_").last
field = self::Fields[method_field.to_sym]
return super unless field
self.where(field, args.first)
end
def method_missing(method, *args)
field = self.class::Fields[method]
return handle_field(field) if field
return super
end
def self.reverse_field(search)
hash = {}
self::Fields.each do |k, v|
hash[v] = k
end
return hash[search]
end
# Returns all objects which have the ObjectClass of the inherited class
def self.all
Adauth.logger.info(self.class.inspect) { "Searching for all objects matching filter \"#{self::ObjectFilter}\"" }
Adauth::SearchResults.new(self.filter(self::ObjectFilter))
end
# Returns all the objects which match the supplied query
#
# Uses ObjectFilter to restrict to the current object
def self.where(field, value)
search_filter = Net::LDAP::Filter.eq(field, value)
Adauth.logger.info(self.class.inspect) { "Searching for all \"#{self::ObjectFilter}\" where #{field} = #{value}" }
Adauth::SearchResults.new(filter(add_object_filter(search_filter)))
end
# Returns all LDAP objects that match the given filter
#
# Use with add_object_filter to make sure that you only get objects that match the object you are querying though
def self.filter(filter)
results = []
result = Adauth.connection.search(:filter => filter)
raise 'Search returned NIL' if result == nil
result.each do |entry|
results << self.new(entry)
end
results
end
# Adds the object filter to the passed filter
def self.add_object_filter(filter)
filter & self::ObjectFilter
end
# Creates a new instance of the object and sets @ldap_object to the passed Net::LDAP entity
def initialize(ldap_object)
expects ldap_object, Net::LDAP::Entry
@ldap_object = ldap_object
end
# Allows direct access to @ldap_object
def ldap_object
@ldap_object
end
# Handle the output for the given field
def handle_field(field)
case field
when Symbol then return return_symbol_value(field)
when Array then return @ldap_object.try(field.first).try(:collect, &field.last)
end
end
# Returns all the groups the object is a member of
def groups
unless @groups
@groups = convert_to_objects(cn_groups)
end
@groups
end
# The same as cn_groups, but with the parent groups included
def cn_groups_nested
@cn_groups_nested = cn_groups
cn_groups.each do |group|
ado = Adauth::AdObjects::Group.where('name', group).first
if ado
groups = convert_to_objects ado.cn_groups
groups.each do |g|
@cn_groups_nested.push g if !(@cn_groups_nested.include?(g))
end
end
end
return @cn_groups_nested
end
# Returns all the ous the object is in
def ous
unless @ous
@ous = []
@ldap_object.dn.split(/,/).each do |entry|
@ous.push Adauth::AdObjects::OU.where('name', entry.gsub(/OU=/, '')).first if entry =~ /OU=/
end
end
@ous
end
# CSV Version of the ous list (can't be pulled over from AD)
def dn_ous
unless @dn_ous
@dn_ous = []
@ldap_object.dn.split(/,/).each do |entry|
@dn_ous.push entry.gsub(/OU=/, '').gsub(/CN=/,'') if entry =~ /OU=/ or entry == "CN=Users"
end
end
@dn_ous
end
# Runs a modify action on the current object, takes an aray of operations
def modify(operations)
Adauth.logger.info(self.class.inspect) { "Attempting modify operation" }
unless Adauth.connection.modify :dn => @ldap_object.dn, :operations => operations
Adauth.logger.fatal(self.class.inspect) { "Modify Operation Failed! Code: #{Adauth.connection.get_operation_result.code} Message: #{Adauth.connection.get_operation_result.message}" }
raise 'Modify Operation Failed (see log for details)'
end
end
# Returns an array of member objects for this object
def members
unless @members
@members = []
[Adauth::AdObjects::Computer, Adauth::AdObjects::OU, Adauth::AdObjects::User, Adauth::AdObjects::Group].each do |object|
object.all.each do |entity|
@members.push entity if entity.is_a_member?(self)
end
end
end
@members
end
# Checks to see if the object is a member of a given parent (though DN)
def is_a_member?(parent)
my_split_dn = @ldap_object.dn.split(",")
parent_split_dn = parent.ldap_object.dn.split(",")
if (my_split_dn.count - 1) == parent_split_dn.count
return true if my_split_dn[1] == parent_split_dn[0]
end
return false
end
# Delete the object
def delete
Adauth.connection.delete(dn: @ldap_object.dn)
end
private
def convert_to_objects(array)
out = []
array.each do |entity|
out.push convert_to_object(entity)
end
out
end
def convert_to_object(entity)
user = Adauth::AdObjects::User.where('sAMAccountName', entity).first
group = Adauth::AdObjects::Group.where('sAMAccountName', entity).first
(user || group)
end
def return_symbol_value(field)
value = @ldap_object.try(field)
case value
when Net::BER::BerIdentifiedArray then return value.first
else return value
end
end
end
end