module ROM::LDAP::Directory::Operations
Public Class Methods
# File lib/rom/ldap/directory/operations.rb, line 10 def self.included(klass) klass.class_eval do extend Dry::Core::Cache end end
Public Instance Methods
@param tuple [Hash] tuple using formatted attribute names.
@return [Entry, FalseClass] created LDAP
entry or false.
@api public
# File lib/rom/ldap/directory/operations.rb, line 134 def add(tuple) dn = tuple.delete(:dn) attrs = canonicalise(tuple) raise(DistinguishedNameError, 'DN is required') unless dn log(__callee__, dn) pdu = client.add(dn: dn, attrs: attrs) pdu.success? ? find(dn) : pdu.success? end
Count all entries under the search base.
@return [Integer]
@api public
# File lib/rom/ldap/directory/operations.rb, line 124 def base_total query(base: base, attributes: %w[objectClass], attributes_only: true).count end
@option :filter [String] @option :password [String]
@return [Boolean]
@api public
# File lib/rom/ldap/directory/operations.rb, line 86 def bind_as(filter:, password:) if (entity = query(filter: filter, max: 1).first) password = password.call if password.respond_to?(:call) pdu = client.bind(username: entity.dn, password: password) pdu.success? else false end rescue BindError false end
Return all attributes for a distinguished name.
@param dn [String]
@return [Array<Entry>]
@api public
# File lib/rom/ldap/directory/operations.rb, line 72 def by_dn(dn) raise(DistinguishedNameError, 'DN is required') unless dn query(base: dn, max: 1, attributes: ALL_ATTRS) end
# File lib/rom/ldap/directory/operations.rb, line 57 def debug(pdu) return unless ::ENV['DEBUG'] logger.debug(pdu.advice) if pdu&.advice logger.debug(pdu.message) if pdu&.message logger.debug(pdu.info) if pdu&.failure? end
@param dn [String] distinguished name.
@return [Entry, FalseClass] deleted LDAP
entry or false.
@api public
# File lib/rom/ldap/directory/operations.rb, line 225 def delete(dn) log(__callee__, dn) entry = find(dn) pdu = if pruneable? controls = [OID[:delete_tree]] client.delete(dn: dn, controls: controls) else client.delete(dn: dn) end pdu.success? ? entry : pdu.success? end
Tuple(s) by dn
@param dn [String] distinguished name
@return [Array<Hash>,Hash]
@raise [DistinguishedNameError] DN not found
# File lib/rom/ldap/directory/operations.rb, line 212 def find(dn) entry = by_dn(dn) raise(DistinguishedNameError, 'DN not found') unless entry entry.one? ? entry.first : entry end
client#rename > client#password_modify > client#update
@param dn [String] distinguished name.
@param tuple [Hash] tuple using formatted attribute names.
@return [Entry, FalseClass] updated LDAP
entry or false.
@api public
# File lib/rom/ldap/directory/operations.rb, line 155 def modify(dn, tuple) log(__callee__, dn) # entry = find(dn) new_dn = tuple.delete(:dn) attrs = canonicalise(tuple) rdn_attr, rdn_val = get_rdn(dn).split('=') # 1. Move rename if new_dn new_rdn = get_rdn(new_dn) parent = get_parent_dn(new_dn) new_rdn_attr, new_rdn_val = new_rdn.split('=') replace = rdn_attr.eql?(new_rdn_attr) pdu = client.rename(dn: dn, rdn: new_rdn, replace: replace, superior: parent) if pdu.success? dn, rdn_attr, rdn_val = new_dn, new_rdn_attr, new_rdn_val end end # 2. Change password if attrs.key?('userPassword') new_pwd = attrs.delete('userPassword') entry = find(dn) old_pwd = entry['userPassword'] pdu = client.password_modify(dn, old_pwd: old_pwd, new_pwd: new_pwd) end # 3. Edit attributes unless attrs.empty? # Adding to RDN values? if attrs.key?(rdn_attr) && !attrs.key?(rdn_val) attrs[rdn_attr] = Array(attrs[rdn_attr]).unshift(rdn_val) end pdu = client.update(dn: dn, ops: attrs.to_a) end pdu.success? ? find(dn) : pdu.success? end
Use connection to communicate with server. If :base is passed, it overwrites the default base keyword.
@option :filter [String, Array] AST or LDAP
string.
Defaults to class attribute.
@param options [Hash] @see Connection::SearchRequest
@return [Array<Entry>] Formatted hash like objects.
@api public
# File lib/rom/ldap/directory/operations.rb, line 28 def query(**options) set, counter = [], 0 filter = options.delete(:filter) || DEFAULT_FILTER # TODO: pageable and search referrals params = { base: base, expression: to_expression(filter), **options # paged: pageable? # return_refs: true # https://tools.ietf.org/html/rfc4511#section-4.5.3 } pdu = client.search(**params) do |dn, attributes| counter += 1 logger.debug("#{counter}: #{dn}") if ::ENV['DEBUG'] set << entity = Entry.new(dn, attributes) yield(entity) if block_given? end debug(pdu) set end
Used by gateway to infer schema at boot.
Limited to 1000 and cached.
@param filter [String] dataset schema filter
@return [Array<Entry>]
@api public
# File lib/rom/ldap/directory/operations.rb, line 107 def query_attributes(filter) fetch_or_store(base, filter) do query( filter: filter, base: base, max: 1_000, # attribute sample size attributes_only: true # paged: false ) end end
Private Instance Methods
Rename the formatted keys of the incoming tuple to their original
server-side format.
@note Used by Directory#add
and Directory#modify
@param tuple [Hash]
@example
# => canonicalise(population_count: 0) => { 'populationCount' => 0 }
@api private
# File lib/rom/ldap/directory/operations.rb, line 276 def canonicalise(tuple) Functions[:tuplify].call(tuple, key_map) end
Parent DN
@return [String]
@api private
# File lib/rom/ldap/directory/operations.rb, line 255 def get_parent_dn(dn) dn.split(',')[1..-1].join(',') end
RDN - relative distinguished name
@return [String]
@api private
# File lib/rom/ldap/directory/operations.rb, line 246 def get_rdn(dn) dn.split(',')[0] end
Log operation attempt
# File lib/rom/ldap/directory/operations.rb, line 261 def log(method, dn) logger.debug("#{self.class}##{method} '#{dn}'") end