class EgovUtils::AuthSource
Constants
- B32
- NETWORK_EXCEPTIONS
Attributes
Public Class Methods
# File lib/egov_utils/auth_source.rb, line 25 def self.authenticate(login, password) providers.collect{|p| AuthSource.new(p).authenticate(login, password) }.compact.first end
# File lib/egov_utils/auth_source.rb, line 17 def self.config YAML.load_file(Rails.root.join('config', 'config.yml'))['ldap'] end
# File lib/egov_utils/auth_source.rb, line 33 def self.find_kerberos_user(login) kerberos_providers.collect{|p| AuthSource.new(p).get_kerberos_user_dn(login) }.compact.first end
# File lib/egov_utils/auth_source.rb, line 29 def self.kerberos_providers config.select{|provider, config| config['kerberos']}.keys end
# File lib/egov_utils/auth_source.rb, line 39 def initialize(provider) require 'net-ldap' @provider = provider raise "EgovUtils::AuthSource#initialize - Non existing provider (#{provider.to_s})" unless self.class.providers.include?(provider) end
# File lib/egov_utils/auth_source.rb, line 21 def self.providers config.keys end
Public Instance Methods
# File lib/egov_utils/auth_source.rb, line 87 def authenticate(login, password) return nil if login.blank? || password.blank? with_timeout do attrs = get_user_dn(login, password) if attrs && attrs[:dn] && authenticate_dn(attrs[:dn], password) Rails.logger.info "AuthSource#authenticate successful for '#{login}' on provider #{provider} - user found" if Rails.logger return attrs.except(:dn) end end rescue *NETWORK_EXCEPTIONS => e raise AuthSourceException.new(e.message) end
Check if a DN (user record) authenticates with the password
# File lib/egov_utils/auth_source.rb, line 120 def authenticate_dn(dn, password) if dn.present? && password.present? initialize_ldap_con(dn, password).bind end end
# File lib/egov_utils/auth_source.rb, line 115 def base_group_filter options['active_directory'] ? Net::LDAP::Filter.eq("objectClass", "group") : Net::LDAP::Filter.eq('objectClass', 'groupOfNames') end
# File lib/egov_utils/auth_source.rb, line 111 def base_user_filter Net::LDAP::Filter.eq("objectClass", "user") & Net::LDAP::Filter.eq("objectCategory", "person") end
# File lib/egov_utils/auth_source.rb, line 76 def encryption case options['method'].to_s when 'ssl' :simple_tls when 'tls' :start_tls else nil end end
# File lib/egov_utils/auth_source.rb, line 101 def get_kerberos_user_dn(login) return nil if login.blank? with_timeout do search_user_dn(login) end rescue *NETWORK_EXCEPTIONS => e raise AuthSourceException.new(e.message) end
# File lib/egov_utils/auth_source.rb, line 179 def group_members(group_dn) ldap_con = initialize_ldap_con(options['bind_dn'], options['password']) results = [] if group_dn ldap_con.search(base: options['base'], filter: base_user_filter & Net::LDAP::Filter.ex('memberOf:1.2.840.113556.1.4.1941', group_dn), attributes: user_search_attributes) do |entry| attrs = get_user_attributes_from_ldap_entry(entry) if attrs attrs[:login] = get_attr(entry, options['attributes']['username']) results << attrs end end end results end
Get host of ldap controller from options.
-
:host
- this just give one host andEgovUtils
just asks that host -
:domain
with:resolve_host
set to true. Domain should be domain for your ldap users.in this configuration ldap controller host is resolved by asking for the <tt>_ldap._tcp.<domain></tt> DNS record and takes first - solve the load balancing of ldap queries.
# File lib/egov_utils/auth_source.rb, line 63 def host if options['host'] options['host'] elsif options['resolve_host'] && options['domain'] host_dns.target.to_s end end
Resolves host name - it is used only if option :resolve_host
is set to true and expect :domain
to be defined as well. ldap controller host is resolved by asking for the _ldap._tcp.<domain>
DNS record and takes first - solve the load balancing of ldap queries.
# File lib/egov_utils/auth_source.rb, line 51 def host_dns require 'resolv' @host_dns = Resolv::DNS.open do |dns| dns.getresource('_ldap._tcp.'+options['domain'], Resolv::DNS::Resource::IN::SRV) end end
# File lib/egov_utils/auth_source.rb, line 168 def member?(user_dn, group_dn) ldap_con = initialize_ldap_con(options['bind_dn'], options['password']) Rails.logger.debug("Membership in group (#{group_dn}) for (#{user_dn})") ldap_con.search(base: user_dn, filter: base_user_filter & Net::LDAP::Filter.ex('memberOf:1.2.840.113556.1.4.1941', group_dn), attributes: ['dn']) do |entry| return true end return false end
# File lib/egov_utils/auth_source.rb, line 196 def onthefly_register? !!options['onthefly_register'] end
# File lib/egov_utils/auth_source.rb, line 45 def options @options ||= self.class.config[provider].dup end
Returns ldap controller port. If :resolve_host
is set to true and option for port is not defined, it uses port from DNS response.
# File lib/egov_utils/auth_source.rb, line 72 def port options['resolve_host'] ? (options['port'] || host_dns.port.to_i) : options['port'] end
# File lib/egov_utils/auth_source.rb, line 200 def register_members_only? options['onthefly_register'] == 'members' end
# File lib/egov_utils/auth_source.rb, line 149 def search_group(q, by_login=false) q = q.to_s.strip return [] unless q.present? results = [] search_filter = base_group_filter & group_search_filters(q) ldap_con = initialize_ldap_con(options['bind_dn'], options['password']) ldap_con.search(:base => options['base'], :filter => search_filter, :attributes => group_search_attributes, :size => 10) do |entry| attrs = get_group_attributes_from_ldap_entry(entry) results << attrs if attrs end results rescue *NETWORK_EXCEPTIONS => e raise AuthSourceException.new(e.message) end
Searches the source for users and returns an array of results
# File lib/egov_utils/auth_source.rb, line 127 def search_user(q, by_login=false) q = q.to_s.strip return [] unless q.present? results = [] search_filter = base_user_filter & user_search_filters(q) ldap_con = initialize_ldap_con(options['bind_dn'], options['password']) ldap_con.search(:base => options['base'], :filter => search_filter, :attributes => user_search_attributes, :size => 10) do |entry| attrs = get_user_attributes_from_ldap_entry(entry) if attrs attrs[:login] = get_attr(entry, options['attributes']['username']) results << attrs end end results rescue *NETWORK_EXCEPTIONS => e raise AuthSourceException.new(e.message) end
Private Instance Methods
# File lib/egov_utils/auth_source.rb, line 355 def b48_to_fixnum(i16, i32) i32 + (i16 * B32) end
# File lib/egov_utils/auth_source.rb, line 336 def get_attr(entry, attr_name) if attr_name.is_a? Array attr_name.collect{|an| get_attr(entry, an).presence }.compact.first.to_s elsif !attr_name.blank? value = entry[attr_name].is_a?(Array) ? entry[attr_name].first : entry[attr_name] value.to_s.force_encoding('UTF-8') end end
# File lib/egov_utils/auth_source.rb, line 238 def get_group_attributes_from_ldap_entry(entry) { :dn => entry.dn, :name => get_attr(entry, 'cn'), :provider => provider, :ldap_uid => get_sid_string( get_attr(entry, 'objectSID') ), :external_uid => entry.dn } end
# File lib/egov_utils/auth_source.rb, line 287 def get_group_dn(**options) ldap_con = initialize_ldap_con(options['bind_dn'], options['password']) ldap_con.search(base: options['base'], filter: base_group_filter & ( options[:sid] ? Net::LDAP::Filter.eq('objectSID', options[:sid]) : group_search_filters(options[:name]) ), attributes: ['dn']) do |entry| return get_attr(entry, 'dn') end end
converts hex representation of SID returned by AD to its string representation
# File lib/egov_utils/auth_source.rb, line 346 def get_sid_string(data) return if data.nil? sid = data.unpack('b x nN V*') sid[1, 2] = Array[nil, b48_to_fixnum(sid[1], sid[2])] 'S-' + sid.compact.join('-') end
# File lib/egov_utils/auth_source.rb, line 227 def get_user_attributes_from_ldap_entry(entry) { :dn => entry.dn, :login => get_attr(entry, options['attributes']['username']), :firstname => get_attr(entry, options['attributes']['first_name']), :lastname => get_attr(entry, options['attributes']['last_name']), :mail => get_attr(entry, options['attributes']['email']), :provider => provider } end
# File lib/egov_utils/auth_source.rb, line 265 def get_user_dn(login, password=nil) ldap_con = nil if options['bind_dn'].include?("$login") ldap_con = initialize_ldap_con(options['bind_dn'].sub("$login", Net::LDAP::DN.escape(login)), password) else ldap_con = initialize_ldap_con(options['bind_dn'], options['password']) end attrs = nil search_filter = base_user_filter & login_filters(login) ldap_con.search( :base => options['base'], :filter => search_filter, :attributes=> user_search_attributes) do |entry| if onthefly_register? attrs = get_user_attributes_from_ldap_entry(entry) else attrs = {:dn => entry.dn} end Rails.logger.debug "DN found for #{login}: #{attrs[:dn]}" if Rails.logger && Rails.logger.debug? end attrs end
# File lib/egov_utils/auth_source.rb, line 261 def group_search_attributes ['dn', 'cn', 'objectSID'] end
# File lib/egov_utils/auth_source.rb, line 332 def group_search_filters(q) Net::LDAP::Filter.begins('cn', q) end
# File lib/egov_utils/auth_source.rb, line 214 def initialize_ldap_con(ldap_user, ldap_password) options = { :host => self.host, :port => self.port, :encryption => encryption } unless ldap_user.blank? && ldap_password.blank? options.merge!(:auth => { :method => :simple, :username => ldap_user, :password => ldap_password }) else options.merge!(:auth => { :method => :anonymous }) end Net::LDAP.new options end
# File lib/egov_utils/auth_source.rb, line 253 def login_attributes if onthefly_register? user_search_attributes else ['dn'] end end
# File lib/egov_utils/auth_source.rb, line 314 def login_filters(login) filters = options['attributes']['username'].collect{|un| Net::LDAP::Filter.eq(un, login)} filters[1..-1].inject(filters.first){|filter, lf| filter | lf } end
# File lib/egov_utils/auth_source.rb, line 319 def login_search_filters(q) filters = options['attributes']['username'].collect{|un| Net::LDAP::Filter.begins(un, q)} filters[1..-1].inject(filters.first){|filter, lf| filter | lf } end
# File lib/egov_utils/auth_source.rb, line 296 def search_user_dn(login, password=nil) ldap_con = nil if options['bind_dn'].include?("$login") ldap_con = initialize_ldap_con(options['bind_dn'].sub("$login", Net::LDAP::DN.escape(login)), password) else ldap_con = initialize_ldap_con(options['bind_dn'], options['password']) end attrs = nil search_filter = login_search_filters(login) #base_filter & Net::LDAP::Filter.eq(self.attr_login, login) ldap_con.search( :base => options['base'], :filter => search_filter, :attributes=> user_search_attributes) do |entry| attrs ||= get_user_attributes_from_ldap_entry(entry) Rails.logger.debug "DN found for #{login}: #{attrs[:dn]}" if Rails.logger && Rails.logger.debug? end attrs end
Return the attributes needed for the LDAP search. It will only include the user attributes if on-the-fly registration is enabled
# File lib/egov_utils/auth_source.rb, line 250 def user_search_attributes ['dn'] + options['attributes']['username'] + options['attributes']['email'] + [options['attributes']['name'], options['attributes']['first_name'], options['attributes']['last_name']] end
# File lib/egov_utils/auth_source.rb, line 324 def user_search_filters(q) Net::LDAP::Filter.begins(options['attributes']['name'], q) | Net::LDAP::Filter.begins(options['attributes']['first_name'], q) | Net::LDAP::Filter.begins(options['attributes']['last_name'], q) | Net::LDAP::Filter.begins(options['attributes']['username'].first, q) | Net::LDAP::Filter.begins(options['attributes']['email'].first, q) end
# File lib/egov_utils/auth_source.rb, line 205 def with_timeout(&block) timeout = 20 Timeout.timeout(timeout) do return yield end rescue Timeout::Error => e raise AuthSourceTimeoutException.new(e.message) end