Class: LDAP::Server::Filter
- Inherits:
-
Object
- Object
- LDAP::Server::Filter
- Defined in:
- lib/ldap/server/filter.rb
Overview
LDAP filters are parsed into a LISP-like internal representation:
[:true]
[:false]
[:undef]
[:and, ..., ..., ...]
[:or, ..., ..., ...]
[:not, ...]
[:present, attr]
[:eq, attr, MO, val]
[:approx, attr, MO, val]
[:substrings, attr, MO, initial=nil, {any, any...}, final=nil]
[:ge, attr, MO, val]
[:le, attr, MO, val]
This is done rather than a more object-oriented approach, in the hope that it will make it easier to match certain filter structures when converting them into something else. e.g. certain LDAP filter constructs can be mapped to some fixed SQL queries.
See RFC 2251 4.5.1 for the three-state(!) boolean logic from LDAP
If no schema is provided: ‘attr’ is the raw attribute name as provided by the client. If a schema is provided: attr is converted to its normalized name as listed in the schema, e.g. ‘commonname’ becomes ‘cn’, ‘objectclass’ becomes ‘objectClass’ etc. If a schema is provided, MO is a matching object which can be used to perform the match. If no schema is provided, this is ‘nil’. In that case you could use LDAP::Server::MatchingRule::DefaultMatch.
Class Method Summary collapse
-
.parse(asn1, schema = nil) ⇒ Object
Parse a filter in OpenSSL::ASN1 format into our own format.
-
.run(filter, av) ⇒ Object
Run a parsed filter against an attr=> hash.
Class Method Details
.parse(asn1, schema = nil) ⇒ Object
Parse a filter in OpenSSL::ASN1 format into our own format.
There are some trivial optimisations we make: e.g.
(&(objectClass=*)(cn=foo)) -> (&(cn=foo)) -> (cn=foo)
44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 |
# File 'lib/ldap/server/filter.rb', line 44 def self.parse(asn1, schema=nil) case asn1.tag when 0 # and conds = asn1.value.collect { |a| parse(a) } conds.delete([:true]) return [:true] if conds.size == 0 return conds.first if conds.size == 1 return [:false] if conds.include?([:false]) return conds.unshift(:and) when 1 # or conds = asn1.value.collect { |a| parse(a) } conds.delete([:false]) return [:false] if conds.size == 0 return conds.first if conds.size == 1 return [:true] if conds.include?([:true]) return conds.unshift(:or) when 2 # not cond = parse(asn1.value[0]) case cond when [:false]; return [:true] when [:true]; return [:false] when [:undef]; return [:undef] end return [:not, cond] when 3 # equalityMatch attr = asn1.value[0].value val = asn1.value[1].value return [:true] if attr =~ /\AobjectClass\z/i and val =~ /\Atop\z/i if schema a = schema.find_attrtype(attr) return [:undef] unless a.equality return [:eq, a.to_s, a.equality, val] end return [:eq, attr, nil, val] when 4 # substrings attr = asn1.value[0].value if schema a = schema.find_attrtype(attr) return [:undef] unless a.substr res = [:substrings, a.to_s, a.substr, nil] else res = [:substrings, attr, nil, nil] end final_val = nil asn1.value[1].value.each do |ss| case ss.tag when 0 res[3] = ss.value when 1 res << ss.value when 2 final_val = ss.value else raise LDAP::ResultError::ProtocolError, "Unrecognised substring tag #{ss.tag.inspect}" end end res << final_val return res when 5 # greaterOrEqual attr = asn1.value[0].value val = asn1.value[1].value if schema a = schema.find_attrtype(attr) return [:undef] unless a.ordering return [:ge, a.to_s, a.ordering, val] end return [:ge, attr, nil, val] when 6 # lessOrEqual attr = asn1.value[0].value val = asn1.value[1].value if schema a = schema.find_attrtype(attr) return [:undef] unless a.ordering return [:le, a.to_s, a.ordering, val] end return [:le, attr, nil, val] when 7 # present attr = asn1.value return [:true] if attr =~ /\AobjectClass\z/i if schema begin a = schema.find_attrtype(attr) return [:present, a.to_s] rescue LDAP::ResultError::UndefinedAttributeType return [:false] end end return [:present, attr] when 8 # approxMatch attr = asn1.value[0].value val = asn1.value[1].value if schema a = schema.find_attrtype(attr) # I don't know how properly to deal with approxMatch. I'm assuming # that the object will have an equality MatchingRule, and we # can defer to that. return [:undef] unless a.equality return [:approx, a.to_s, a.equality, val] end return [:approx, attr, nil, val] #when 9 # extensibleMatch # FIXME else raise LDAP::ResultError::ProtocolError, "Unrecognised Filter tag #{asn1.tag}" end # Unknown attribute type rescue LDAP::ResultError::UndefinedAttributeType return [:undef] end |
.run(filter, av) ⇒ Object
Run a parsed filter against an attr=> hash.
Returns true, false or nil.
172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 |
# File 'lib/ldap/server/filter.rb', line 172 def self.run(filter, av) case filter[0] when :and res = true filter[1..-1].each do |elem| r = run(elem, av) return false if r == false res = nil if r.nil? end return res when :or res = false filter[1..-1].each do |elem| r = run(elem, av) return true if r == true res = nil if r.nil? end return res when :not case run(filter[1], av) when true; return false when false; return true else return nil end when :present return av.has_key?(filter[1]) when :eq, :approx, :le, :ge, :substrings # the filter now includes a suitable matching object return (filter[2] || LDAP::Server::MatchingRule::DefaultMatch).send( filter.first, av[filter[1].to_s], *filter[3..-1]) when :true return true when :false return false when :undef return nil end raise LDAP::ResultError::OperationsError, "Unimplemented filter #{filter.first.inspect}" end |