Added Net::LDAP::Filter.parse_ber and associated helper methods and tests.
This commit is contained in:
parent
bc1129fcf1
commit
da882af074
5
Rakefile
5
Rakefile
|
@ -75,6 +75,11 @@ task :test_snmp do |t|
|
||||||
run_test_set t, ['tests/testsnmp.rb', 'tests/testber.rb']
|
run_test_set t, ['tests/testsnmp.rb', 'tests/testber.rb']
|
||||||
end
|
end
|
||||||
|
|
||||||
|
desc "(Provisional) Run tests for filters"
|
||||||
|
task :test_filters do |t|
|
||||||
|
run_test_set t, ['tests/testfilter.rb']
|
||||||
|
end
|
||||||
|
|
||||||
spec = eval(File.read("net-ldap.gemspec"))
|
spec = eval(File.read("net-ldap.gemspec"))
|
||||||
spec.version = $version
|
spec.version = $version
|
||||||
desc "Build the RubyGem for #$name."
|
desc "Build the RubyGem for #$name."
|
||||||
|
|
|
@ -311,6 +311,8 @@ module Net
|
||||||
2 => :array, # SearchFilter-NOT
|
2 => :array, # SearchFilter-NOT
|
||||||
3 => :array, # Seach referral
|
3 => :array, # Seach referral
|
||||||
4 => :array, # unknown use in Microsoft Outlook
|
4 => :array, # unknown use in Microsoft Outlook
|
||||||
|
5 => :array, # SearchFilter-GE
|
||||||
|
6 => :array, # SearchFilter-LE
|
||||||
7 => :array, # serverSaslCreds
|
7 => :array, # serverSaslCreds
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -115,6 +115,11 @@ class Filter
|
||||||
# Removed GT and LT. They're not in the RFC.
|
# Removed GT and LT. They're not in the RFC.
|
||||||
def ~@; Filter.new :not, self, nil; end
|
def ~@; Filter.new :not, self, nil; end
|
||||||
|
|
||||||
|
# Equality operator for filters, useful primarily for constructing unit tests.
|
||||||
|
def == filter
|
||||||
|
str = "[@op,@left,@right]"
|
||||||
|
self.instance_eval(str) == filter.instance_eval(str)
|
||||||
|
end
|
||||||
|
|
||||||
def to_s
|
def to_s
|
||||||
case @op
|
case @op
|
||||||
|
@ -224,6 +229,58 @@ class Filter
|
||||||
end
|
end
|
||||||
end
|
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 #to_ber, including the grammar snippet from the RFC.
|
||||||
|
#--
|
||||||
|
# We're hardcoding the BER constants from the RFC. Ought to break them out
|
||||||
|
# into constants.
|
||||||
|
#
|
||||||
|
def Filter::parse_ber ber
|
||||||
|
case ber.ber_identifier
|
||||||
|
when 0xa0 # context-specific constructed 0, "and"
|
||||||
|
ber.map {|b| Filter::parse_ber(b)}.inject {|memo,obj| memo & obj}
|
||||||
|
when 0xa1 # context-specific constructed 1, "or"
|
||||||
|
ber.map {|b| Filter::parse_ber(b)}.inject {|memo,obj| memo | obj}
|
||||||
|
when 0xa2 # context-specific constructed 2, "not"
|
||||||
|
~ Filter::parse_ber( ber.first )
|
||||||
|
when 0xa3 # context-specific constructed 3, "equalityMatch"
|
||||||
|
if ber.last == "*"
|
||||||
|
else
|
||||||
|
Filter.eq( ber.first, ber.last )
|
||||||
|
end
|
||||||
|
when 0xa4 # context-specific constructed 4, "substring"
|
||||||
|
str = ""
|
||||||
|
final = false
|
||||||
|
ber.last.each {|b|
|
||||||
|
case b.ber_identifier
|
||||||
|
when 0x80 # context-specific primitive 0, SubstringFilter "initial"
|
||||||
|
raise "unrecognized substring filter, bad initial" if str.length > 0
|
||||||
|
str += b
|
||||||
|
when 0x81 # context-specific primitive 0, SubstringFilter "any"
|
||||||
|
str += "*#{b}"
|
||||||
|
when 0x82 # context-specific primitive 0, SubstringFilter "final"
|
||||||
|
str += "*#{b}"
|
||||||
|
final = true
|
||||||
|
end
|
||||||
|
}
|
||||||
|
str += "*" unless final
|
||||||
|
Filter.eq( ber.first.to_s, str )
|
||||||
|
when 0xa5 # context-specific constructed 5, "greaterOrEqual"
|
||||||
|
Filter.ge( ber.first.to_s, ber.last.to_s )
|
||||||
|
when 0xa6 # context-specific constructed 5, "lessOrEqual"
|
||||||
|
Filter.le( ber.first.to_s, ber.last.to_s )
|
||||||
|
when 0x87 # context-specific primitive 7, "present"
|
||||||
|
# call to_s to get rid of the BER-identifiedness of the incoming string.
|
||||||
|
Filter.pres( ber.to_s )
|
||||||
|
else
|
||||||
|
raise "invalid BER tag-value (#{ber.ber_identifier}) in search filter"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
#--
|
#--
|
||||||
# coalesce
|
# coalesce
|
||||||
# This is a private helper method for dealing with chains of ANDs and ORs
|
# This is a private helper method for dealing with chains of ANDs and ORs
|
||||||
|
@ -260,6 +317,8 @@ class Filter
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#--
|
#--
|
||||||
# We got a hash of attribute values.
|
# We got a hash of attribute values.
|
||||||
# Do we match the attributes?
|
# Do we match the attributes?
|
||||||
|
|
|
@ -11,27 +11,88 @@ require 'net/ldap'
|
||||||
|
|
||||||
class TestFilter < Test::Unit::TestCase
|
class TestFilter < Test::Unit::TestCase
|
||||||
|
|
||||||
def setup
|
def setup
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
def teardown
|
def teardown
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_rfc_2254
|
# Note that the RFC doesn't define either less-than or greater-than.
|
||||||
p Net::LDAP::Filter.from_rfc2254( " ( uid=george* ) " )
|
def test_rfc_2254
|
||||||
p Net::LDAP::Filter.from_rfc2254( "uid!=george*" )
|
Net::LDAP::Filter.from_rfc2254( " ( uid=george* ) " )
|
||||||
p Net::LDAP::Filter.from_rfc2254( "uid<george*" )
|
Net::LDAP::Filter.from_rfc2254( "uid!=george*" )
|
||||||
p Net::LDAP::Filter.from_rfc2254( "uid <= george*" )
|
Net::LDAP::Filter.from_rfc2254( "uid <= george*" )
|
||||||
p Net::LDAP::Filter.from_rfc2254( "uid>george*" )
|
Net::LDAP::Filter.from_rfc2254( "uid>=george*" )
|
||||||
p Net::LDAP::Filter.from_rfc2254( "uid>=george*" )
|
Net::LDAP::Filter.from_rfc2254( "uid!=george*" )
|
||||||
p Net::LDAP::Filter.from_rfc2254( "uid!=george*" )
|
|
||||||
|
|
||||||
p Net::LDAP::Filter.from_rfc2254( "(& (uid!=george* ) (mail=*))" )
|
Net::LDAP::Filter.from_rfc2254( "(& (uid!=george* ) (mail=*))" )
|
||||||
p Net::LDAP::Filter.from_rfc2254( "(| (uid!=george* ) (mail=*))" )
|
Net::LDAP::Filter.from_rfc2254( "(| (uid!=george* ) (mail=*))" )
|
||||||
p Net::LDAP::Filter.from_rfc2254( "(! (mail=*))" )
|
Net::LDAP::Filter.from_rfc2254( "(! (mail=*))" )
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_filters_from_ber
|
||||||
|
[
|
||||||
|
Net::LDAP::Filter.eq( "objectclass", "*" ),
|
||||||
|
Net::LDAP::Filter.pres( "objectclass" ),
|
||||||
|
Net::LDAP::Filter.eq( "objectclass", "ou" ),
|
||||||
|
Net::LDAP::Filter.ge( "uid", "500" ),
|
||||||
|
Net::LDAP::Filter.le( "uid", "500" ),
|
||||||
|
(~ Net::LDAP::Filter.pres( "objectclass" )),
|
||||||
|
(Net::LDAP::Filter.pres( "objectclass" ) & Net::LDAP::Filter.pres( "ou" )),
|
||||||
|
(Net::LDAP::Filter.pres( "objectclass" ) & Net::LDAP::Filter.pres( "ou" ) & Net::LDAP::Filter.pres("sn")),
|
||||||
|
(Net::LDAP::Filter.pres( "objectclass" ) | Net::LDAP::Filter.pres( "ou" ) | Net::LDAP::Filter.pres("sn")),
|
||||||
|
|
||||||
|
Net::LDAP::Filter.eq( "objectclass", "*aaa" ),
|
||||||
|
Net::LDAP::Filter.eq( "objectclass", "*aaa*bbb" ),
|
||||||
|
Net::LDAP::Filter.eq( "objectclass", "*aaa*bbb*ccc" ),
|
||||||
|
Net::LDAP::Filter.eq( "objectclass", "aaa*bbb" ),
|
||||||
|
Net::LDAP::Filter.eq( "objectclass", "aaa*bbb*ccc" ),
|
||||||
|
Net::LDAP::Filter.eq( "objectclass", "abc*def*1111*22*g" ),
|
||||||
|
Net::LDAP::Filter.eq( "objectclass", "*aaa*" ),
|
||||||
|
Net::LDAP::Filter.eq( "objectclass", "*aaa*bbb*" ),
|
||||||
|
Net::LDAP::Filter.eq( "objectclass", "*aaa*bbb*ccc*" ),
|
||||||
|
Net::LDAP::Filter.eq( "objectclass", "aaa*" ),
|
||||||
|
Net::LDAP::Filter.eq( "objectclass", "aaa*bbb*" ),
|
||||||
|
Net::LDAP::Filter.eq( "objectclass", "aaa*bbb*ccc*" ),
|
||||||
|
].each {|ber|
|
||||||
|
f = Net::LDAP::Filter.parse_ber( ber.to_ber.read_ber( Net::LDAP::AsnSyntax) )
|
||||||
|
assert( f == ber )
|
||||||
|
assert_equal( f.to_ber, ber.to_ber )
|
||||||
|
}
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_ber_from_rfc2254_filter
|
||||||
|
[
|
||||||
|
Net::LDAP::Filter.construct( "objectclass=*" ),
|
||||||
|
Net::LDAP::Filter.construct("objectclass=ou" ),
|
||||||
|
Net::LDAP::Filter.construct("uid >= 500" ),
|
||||||
|
Net::LDAP::Filter.construct("uid <= 500" ),
|
||||||
|
Net::LDAP::Filter.construct("(!(uid=*))" ),
|
||||||
|
Net::LDAP::Filter.construct("(&(uid=*)(objectclass=*))" ),
|
||||||
|
Net::LDAP::Filter.construct("(&(uid=*)(objectclass=*)(sn=*))" ),
|
||||||
|
Net::LDAP::Filter.construct("(|(uid=*)(objectclass=*))" ),
|
||||||
|
Net::LDAP::Filter.construct("(|(uid=*)(objectclass=*)(sn=*))" ),
|
||||||
|
|
||||||
|
Net::LDAP::Filter.construct("objectclass=*aaa"),
|
||||||
|
Net::LDAP::Filter.construct("objectclass=*aaa*bbb"),
|
||||||
|
Net::LDAP::Filter.construct("objectclass=*aaa*bbb*ccc"),
|
||||||
|
Net::LDAP::Filter.construct("objectclass=aaa*bbb"),
|
||||||
|
Net::LDAP::Filter.construct("objectclass=aaa*bbb*ccc"),
|
||||||
|
Net::LDAP::Filter.construct("objectclass=abc*def*1111*22*g"),
|
||||||
|
Net::LDAP::Filter.construct("objectclass=*aaa*"),
|
||||||
|
Net::LDAP::Filter.construct("objectclass=*aaa*bbb*"),
|
||||||
|
Net::LDAP::Filter.construct("objectclass=*aaa*bbb*ccc*"),
|
||||||
|
Net::LDAP::Filter.construct("objectclass=aaa*"),
|
||||||
|
Net::LDAP::Filter.construct("objectclass=aaa*bbb*"),
|
||||||
|
Net::LDAP::Filter.construct("objectclass=aaa*bbb*ccc*"),
|
||||||
|
].each {|ber|
|
||||||
|
f = Net::LDAP::Filter.parse_ber( ber.to_ber.read_ber( Net::LDAP::AsnSyntax) )
|
||||||
|
assert( f == ber )
|
||||||
|
assert_equal( f.to_ber, ber.to_ber )
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue