Parent

Net::LDAP::Filter

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.

Public Class Methods

construct(ldap_filter_string) click to toggle source

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
eq(attribute, value;) click to toggle source

# 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
from_rfc2254(ldap_filter_string) click to toggle source

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
ge(attribute, value;) click to toggle source

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
le(attribute, value;) click to toggle source
    # File lib/net/ldap/filter.rb, line 82
82:   def Filter::le attribute, value; Filter.new :le, attribute, value; end
ne(attribute, value;) click to toggle source
    # File lib/net/ldap/filter.rb, line 78
78:   def Filter::ne attribute, value; Filter.new :ne, attribute, value; end
new(op, a, b) click to toggle source
    # 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
parse_ber(ber) click to toggle source

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
parse_ldap_filter(obj) click to toggle source
     # 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
pres(attribute;) click to toggle source

pres( attribute ) is a synonym for #( attribute, “*” )

    # File lib/net/ldap/filter.rb, line 86
86:   def Filter::pres attribute; Filter.eq attribute, "*"; end

Public Instance Methods

&(filter;) click to toggle source

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
==(filter) click to toggle source

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
coalesce(operator) click to toggle source
     # 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
execute(&block) click to toggle source

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
match(entry) click to toggle source
     # 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
to_ber() click to toggle source
     # 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
to_s() click to toggle source
     # 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
unescape(right) click to toggle source
     # 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
|(filter;) click to toggle source

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
~() click to toggle source

operator ~ (“NOT”) is used to negate a filter. This expression will select only entries that do not have an objectclass attribute:

 f = ~ Net::LDAP::Filter.pres( "objectclass" )
     # File lib/net/ldap/filter.rb, line 112
112:   def ~; Filter.new :not, self, nil; end

Disabled; run with --debug to generate this.

[Validate]

Generated with the Darkfish Rdoc Generator 1.1.6.