Object
Class Net::LDAP::Filter is used to constrain LDAP searches. An object of this class is passed to Net::LDAP#search in the parameter :filter.
Net::LDAP::Filter supports the complete set of search filters available in LDAP, including conjunction, disjunction and negation (AND, OR, and NOT). This class supplants the (infamous) RFC-2254 standard notation for specifying LDAP search filters.
Here’s how to code the familiar “objectclass is present” filter:
f = Net::LDAP::Filter.pres( "objectclass" )
The object returned by this code can be passed directly to the :filter parameter of Net::LDAP#search.
See the individual class and instance methods below for more examples.
Converts an LDAP filter-string (in the prefix syntax specified in RFC-2254) to a Net::LDAP::Filter.
# File lib/net/ldap/filter.rb, line 388 388: def self.construct ldap_filter_string 389: FilterParser.new(ldap_filter_string).filter 390: end
# creates a filter object indicating that the value of a paticular attribute must be either present or must match a particular string.
To specify that an attribute is “present” means that only directory entries which contain a value for the particular attribute will be selected by the filter. This is useful in case of optional attributes such as mail. Presence is indicated by giving the value “*” in the second parameter to #. This example selects only entries that have one or more values for sAMAccountName:
f = Net::LDAP::Filter.eq( "sAMAccountName", "*" )
To match a particular range of values, pass a string as the second parameter to #. The string may contain one or more “*” characters as wildcards: these match zero or more occurrences of any character. Full regular-expressions are not supported due to limitations in the underlying LDAP protocol. This example selects any entry with a mail value containing the substring “anderson”:
f = Net::LDAP::Filter.eq( "mail", "*anderson*" )
# File lib/net/ldap/filter.rb, line 77 77: def Filter::eq attribute, value; Filter.new :eq, attribute, value; end
Synonym for #. to a Net::LDAP::Filter.
# File lib/net/ldap/filter.rb, line 394 394: def self.from_rfc2254 ldap_filter_string 395: construct ldap_filter_string 396: end
def Filter::gt attribute, value; Filter.new :gt, attribute, value; end def Filter::lt attribute, value; Filter.new :lt, attribute, value; end
# File lib/net/ldap/filter.rb, line 81 81: def Filter::ge attribute, value; Filter.new :ge, attribute, value; end
# File lib/net/ldap/filter.rb, line 82 82: def Filter::le attribute, value; Filter.new :le, attribute, value; end
# File lib/net/ldap/filter.rb, line 78 78: def Filter::ne attribute, value; Filter.new :ne, attribute, value; end
# File lib/net/ldap/filter.rb, line 47 47: def initialize op, a, b 48: @op = op 49: @left = a 50: @right = b 51: end
Converts an LDAP search filter in BER format to an Net::LDAP::Filter object. The incoming BER object most likely came to us by parsing an LDAP searchRequest PDU. Cf the comments under #, including the grammar snippet from the RFC.
# File lib/net/ldap/filter.rb, line 243 243: def Filter::parse_ber ber 244: case ber.ber_identifier 245: when 0xa0 # context-specific constructed 0, "and" 246: ber.map {|b| Filter::parse_ber(b)}.inject {|memo,obj| memo & obj} 247: when 0xa1 # context-specific constructed 1, "or" 248: ber.map {|b| Filter::parse_ber(b)}.inject {|memo,obj| memo | obj} 249: when 0xa2 # context-specific constructed 2, "not" 250: ~ Filter::parse_ber( ber.first ) 251: when 0xa3 # context-specific constructed 3, "equalityMatch" 252: if ber.last == "*" 253: else 254: Filter.eq( ber.first, ber.last ) 255: end 256: when 0xa4 # context-specific constructed 4, "substring" 257: str = "" 258: final = false 259: ber.last.each {|b| 260: case b.ber_identifier 261: when 0x80 # context-specific primitive 0, SubstringFilter "initial" 262: raise "unrecognized substring filter, bad initial" if str.length > 0 263: str += b 264: when 0x81 # context-specific primitive 0, SubstringFilter "any" 265: str += "*#{b}" 266: when 0x82 # context-specific primitive 0, SubstringFilter "final" 267: str += "*#{b}" 268: final = true 269: end 270: } 271: str += "*" unless final 272: Filter.eq( ber.first.to_s, str ) 273: when 0xa5 # context-specific constructed 5, "greaterOrEqual" 274: Filter.ge( ber.first.to_s, ber.last.to_s ) 275: when 0xa6 # context-specific constructed 5, "lessOrEqual" 276: Filter.le( ber.first.to_s, ber.last.to_s ) 277: when 0x87 # context-specific primitive 7, "present" 278: # call to_s to get rid of the BER-identifiedness of the incoming string. 279: Filter.pres( ber.to_s ) 280: else 281: raise "invalid BER tag-value (#{ber.ber_identifier}) in search filter" 282: end 283: end
# File lib/net/ldap/filter.rb, line 355 355: def Filter::parse_ldap_filter obj 356: case obj.ber_identifier 357: when 0x87 # present. context-specific primitive 7. 358: Filter.eq( obj.to_s, "*" ) 359: when 0xa3 # equalityMatch. context-specific constructed 3. 360: Filter.eq( obj[0], obj[1] ) 361: else 362: raise LdapError.new( "unknown ldap search-filter type: #{obj.ber_identifier}" ) 363: end 364: end
operator & (“AND”) is used to conjoin two or more filters. This expression will select only entries that have an objectclass attribute AND have a mail attribute that begins with “George”:
f = Net::LDAP::Filter.pres( "objectclass" ) & Net::LDAP::Filter.eq( "mail", "George*" )
# File lib/net/ldap/filter.rb, line 93 93: def & filter; Filter.new :and, self, filter; end
Equality operator for filters, useful primarily for constructing unit tests.
# File lib/net/ldap/filter.rb, line 115 115: def == filter 116: str = "[@op,@left,@right]" 117: self.instance_eval(str) == filter.instance_eval(str) 118: end
# File lib/net/ldap/filter.rb, line 339 339: def coalesce operator 340: if @op == operator 341: [@left.coalesce( operator ), @right.coalesce( operator )] 342: else 343: [self] 344: end 345: end
Perform filter operations against a user-supplied block. This is useful when implementing an LDAP directory server. The caller’s block will be called with two arguments: first, a symbol denoting the “operation” of the filter; and second, an array consisting of arguments to the operation. The user-supplied block (which is MANDATORY) should perform some desired application-defined processing, and may return a locally-meaningful object that will appear as a parameter in the :and, :or and :not operations detailed below.
A typical object to return from the user-supplied block is an array of Net::LDAP::Filter objects.
These are the possible values that may be passed to the user-supplied block:
:equalityMatch (the arguments will be an attribute name and a value to be matched); :substrings (two arguments: an attribute name and a value containing one or more * characters); :present (one argument: an attribute name); :greaterOrEqual (two arguments: an attribute name and a value to be compared against); :lessOrEqual (two arguments: an attribute name and a value to be compared against); :and (two or more arguments, each of which is an object returned from a recursive call to #execute, with the same block; :or (two or more arguments, each of which is an object returned from a recursive call to #execute, with the same block; :not (one argument, which is an object returned from a recursive call to #execute with the the same block.
# File lib/net/ldap/filter.rb, line 309 309: def execute &block 310: case @op 311: when :eq 312: if @right == "*" 313: yield :present, @left 314: elsif @right.index '*' 315: yield :substrings, @left, @right 316: else 317: yield :equalityMatch, @left, @right 318: end 319: when :ge 320: yield :greaterOrEqual, @left, @right 321: when :le 322: yield :lessOrEqual, @left, @right 323: when :or, :and 324: yield @op, (@left.execute(&block)), (@right.execute(&block)) 325: when :not 326: yield @op, (@left.execute(&block)) 327: end || [] 328: end
# File lib/net/ldap/filter.rb, line 373 373: def match entry 374: case @op 375: when :eq 376: if @right == "*" 377: l = entry[@left] and l.length > 0 378: else 379: l = entry[@left] and l = l.to_a and l.index(@right) 380: end 381: else 382: raise LdapError.new( "unknown filter type in match: #{@op}" ) 383: end 384: end
# File lib/net/ldap/filter.rb, line 183 183: def to_ber 184: case @op 185: when :eq 186: if @right == "*" # present 187: @left.to_s.to_ber_contextspecific 7 188: elsif @right =~ /[\*]/ #substring 189: ary = @right.split( /[\*]+/ ) 190: final_star = @right =~ /[\*]$/ 191: initial_star = ary.first == "" and ary.shift 192: 193: seq = [] 194: unless initial_star 195: seq << ary.shift.to_ber_contextspecific(0) 196: end 197: n_any_strings = ary.length - (final_star ? 0 : 1) 198: #p n_any_strings 199: n_any_strings.times { 200: seq << ary.shift.to_ber_contextspecific(1) 201: } 202: unless final_star 203: seq << ary.shift.to_ber_contextspecific(2) 204: end 205: [@left.to_s.to_ber, seq.to_ber].to_ber_contextspecific 4 206: else #equality 207: [@left.to_s.to_ber, unescape(@right).to_ber].to_ber_contextspecific 3 208: end 209: when :ge 210: [@left.to_s.to_ber, unescape(@right).to_ber].to_ber_contextspecific 5 211: when :le 212: [@left.to_s.to_ber, unescape(@right).to_ber].to_ber_contextspecific 6 213: when :and 214: ary = [@left.coalesce(:and), @right.coalesce(:and)].flatten 215: ary.map {|a| a.to_ber}.to_ber_contextspecific( 0 ) 216: when :or 217: ary = [@left.coalesce(:or), @right.coalesce(:or)].flatten 218: ary.map {|a| a.to_ber}.to_ber_contextspecific( 1 ) 219: when :not 220: [@left.to_ber].to_ber_contextspecific 2 221: else 222: # ERROR, we'll return objectclass=* to keep things from blowing up, 223: # but that ain't a good answer and we need to kick out an error of some kind. 224: raise "unimplemented search filter" 225: end 226: end
# File lib/net/ldap/filter.rb, line 120 120: def to_s 121: case @op 122: when :ne 123: "(!(#{@left}=#{@right}))" 124: when :eq 125: "(#{@left}=#{@right})" 126: #when :gt 127: # "#{@left}>#{@right}" 128: #when :lt 129: # "#{@left}<#{@right}" 130: when :ge 131: "#{@left}>=#{@right}" 132: when :le 133: "#{@left}<=#{@right}" 134: when :and 135: "(&(#{@left})(#{@right}))" 136: when :or 137: "(|(#{@left})(#{@right}))" 138: when :not 139: "(!(#{@left}))" 140: else 141: raise "invalid or unsupported operator in LDAP Filter" 142: end 143: end
# File lib/net/ldap/filter.rb, line 228 228: def unescape(right) 229: right.gsub(/\\([a-fA-F\d]{2,2})/) do 230: [$1.hex].pack("U") 231: end 232: end
operator | (“OR”) is used to disjoin two or more filters. This expression will select entries that have either an objectclass attribute OR a mail attribute that begins with “George”:
f = Net::LDAP::Filter.pres( "objectclass" ) | Net::LDAP::Filter.eq( "mail", "George*" )
# File lib/net/ldap/filter.rb, line 100 100: def | filter; Filter.new :or, self, filter; end
Disabled; run with --debug to generate this.
Generated with the Darkfish Rdoc Generator 1.1.6.