123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185 |
- class Ldap
-
- class User
- include Ldap::FilterLookup
- IGNORED_ATTRIBUTES = %i[
- admincount
- accountexpires
- badpasswordtime
- badpwdcount
- countrycode
- distinguishedname
- dnshostname
- dscorepropagationdata
- instancetype
- iscriticalsystemobject
- useraccountcontrol
- usercertificate
- objectclass
- objectcategory
- objectsid
- primarygroupid
- pwdlastset
- lastlogoff
- lastlogon
- lastlogontimestamp
- localpolicyflags
- lockouttime
- logoncount
- logonhours
- msdfsr-computerreferencebl
- msds-supportedencryptiontypes
- ridsetreferences
- samaccounttype
- memberof
- serverreferencebl
- serviceprincipalname
- showinadvancedviewonly
- usnchanged
- usncreated
- whenchanged
- whencreated
- ].freeze
-
-
-
-
-
-
-
-
- def self.uid_attribute(attributes)
- result = nil
- %i[objectguid entryuuid samaccountname userprincipalname uid dn].each do |attribute|
- next if attributes[attribute].blank?
- result = attribute.to_s
- break
- end
- result
- end
-
-
-
-
-
-
-
-
-
-
-
- def initialize(config, ldap: nil)
- @config = config
- @ldap = ldap || ::Ldap.new(@config)
- handle_config
- end
-
-
-
-
-
-
-
-
-
-
- def valid?(username, password)
- bind_success = @ldap.connection.bind_as(
- base: @ldap.base_dn,
- filter: @user_filter ? "(&(#{login_attribute}=#{username})#{@user_filter})" : "(#{login_attribute}=#{username})",
- password: password
- )
- message = bind_success ? 'successful' : 'failed'
- Rails.logger.info "ldap authentication for user '#{username}' (#{login_attribute}) #{message}!"
- bind_success.present?
- end
-
-
-
-
-
-
-
-
-
-
- def attributes(custom_filter: nil, base_dn: nil)
- @attributes ||= begin
- attributes = {}.with_indifferent_access
- lookup_counter = 0
-
- @ldap.search(custom_filter || filter, base: base_dn) do |entry|
- pre_merge_count = attributes.count
- attributes.reverse_merge!(entry.to_h
- .except(*IGNORED_ATTRIBUTES)
- .transform_values(&:first)
- .compact)
-
- lookup_counter = (pre_merge_count < attributes.count ? 0 : lookup_counter.next)
- break if lookup_counter >= 50
- end
-
- attributes.each do |name, value|
- attributes[name] = if value.encoding == Encoding.find('ascii-8bit')
- "#{name} (binary data)"
- else
- "#{name} (e.g., #{value.utf8_encode})"
- end
- end
- end
- end
-
-
-
-
-
-
-
- def filter
- @filter ||= lookup_filter(['(&(objectClass=user)(samaccountname=*)(!(samaccountname=*$)))', '(objectClass=user)', '(objectClass=posixaccount)', '(objectClass=person)'])
- end
-
-
-
-
-
-
-
- def uid_attribute
- @uid_attribute ||= self.class.uid_attribute(attributes)
- end
- private
- attr_reader :config
- def login_attribute
- @login_attribute ||= config[:user_attributes]&.key('login') || uid_attribute
- end
- def handle_config
- return if config.blank?
- @uid_attribute = config[:uid_attribute]
- @filter = config[:filter]
- @user_filter = config[:user_filter]
- end
- end
- end
|