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.