Module: Identizer::Ldap::Filter

Defined in:
lib/identizer/ldap/filter.rb

Overview

Matches an LDAP search filter (as parsed by Net::LDAP’s BER reader) against an entry’s attribute hash. Operates directly on the BER structure, keyed by ber_identifier, so it supports the compound filters Net::LDAP::Filter#match does not (and / or / not), plus equality, presence and substrings.

Constant Summary collapse

AND =
0xa0
OR =
0xa1
NOT =
0xa2
EQUALITY =
0xa3
SUBSTRING =
0xa4
PRESENT =
0x87

Class Method Summary collapse

Class Method Details

.equality?(filter, attributes) ⇒ Boolean

Returns:

  • (Boolean)


31
32
33
34
# File 'lib/identizer/ldap/filter.rb', line 31

def equality?(filter, attributes)
  wanted = filter[1].to_s
  values(attributes, filter[0].to_s).any? { |value| value.casecmp?(wanted) }
end

.match?(filter, attributes) ⇒ Boolean

Returns:

  • (Boolean)


19
20
21
22
23
24
25
26
27
28
29
# File 'lib/identizer/ldap/filter.rb', line 19

def match?(filter, attributes)
  case filter.ber_identifier
  when AND       then filter.all? { |sub| match?(sub, attributes) }
  when OR        then filter.any? { |sub| match?(sub, attributes) }
  when NOT       then !match?(filter.first, attributes)
  when EQUALITY  then equality?(filter, attributes)
  when SUBSTRING then substring?(filter, attributes)
  when PRESENT   then present?(filter, attributes)
  else true # unsupported filter types match everything (permissive for a test IdP)
  end
end

.present?(filter, attributes) ⇒ Boolean

Returns:

  • (Boolean)


36
37
38
39
40
41
# File 'lib/identizer/ldap/filter.rb', line 36

def present?(filter, attributes)
  name = filter.to_s
  return true if name.casecmp?("objectclass")

  !values(attributes, name).empty?
end

.substring?(filter, attributes) ⇒ Boolean

Returns:

  • (Boolean)


43
44
45
46
47
48
49
# File 'lib/identizer/ldap/filter.rb', line 43

def substring?(filter, attributes)
  parts = Array(filter[1]).map { |part| Regexp.escape(part.to_s) }
  return true if parts.empty?

  pattern = Regexp.new(parts.join(".*"), Regexp::IGNORECASE)
  values(attributes, filter[0].to_s).any? { |value| pattern.match?(value) }
end

.values(attributes, name) ⇒ Object

Case-insensitive attribute lookup -> array of string values.



52
53
54
55
# File 'lib/identizer/ldap/filter.rb', line 52

def values(attributes, name)
  key = attributes.keys.find { |candidate| candidate.to_s.casecmp?(name) }
  key ? Array(attributes[key]).map(&:to_s) : []
end