You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

289 lines
7.9 KiB

require File.dirname(__FILE__) + '/test_helper'
Thread.abort_on_exception = true
# This test suite requires the ruby-ldap client library to be installed.
#
# Unfortunately, this library is not ruby thread-safe (it blocks until
# it gets a response). Hence we have to fork a child to perform the actual
# LDAP requests, which is nasty. However, it does give us a completely
# independent source of LDAP packets to try.
require 'ldap/server/operation'
require 'ldap/server/server'
require 'net/ldap'
# We subclass the Operation class, overriding the methods to do what we need
class MockOperation < LDAP::Server::Operation
def initialize(connection, messageId)
super(connection, messageId)
@@lastop = [:connect]
end
def simple_bind(version, user, pass)
@@lastop = [:simple_bind, version.to_i, user, pass]
end
def search(basedn, scope, deref, filter)
@@lastop = [:search, basedn, scope.to_i, deref.to_i, filter, @attributes]
send_SearchResultEntry("cn=foo", {"a"=>["1","2"], "b"=>"boing"})
send_SearchResultEntry("cn=bar", {"a"=>["3","4","5"], "b"=>"wibble"})
end
def add(dn, av)
@@lastop = [:add, dn, av]
end
def del(dn)
@@lastop = [:del, dn]
end
def modify(dn, ops)
@@lastop = [:modify, dn, ops]
end
def modifydn(dn, newrdn, deleteoldrdn, newSuperior)
@@lastop = [:modifydn, dn, newrdn, deleteoldrdn, newSuperior]
end
def compare(dn, attr, val)
@@lastop = [:compare, dn, attr, val]
return val != "false"
end
def self.lastop
@@lastop
end
end
class TestLdap < Test::Unit::TestCase
HOST = '127.0.0.1'
PORT = 1389
def start_client
in_ = Queue.new
out = Queue.new
Thread.new do
do_child(in_, out)
end
return in_, out
end
def ensure_server_started
@serv || start_server
end
def start_server(opts={})
# back to a single process (the parent). Now we start our
# listener thread
@serv = LDAP::Server.new({
:bindaddr => '127.0.0.1',
:port => PORT,
:nodelay => true,
:operation_class => MockOperation,
}.merge(opts))
@serv.run_tcpserver
end
def setup
@client = nil
@serv = nil
end
def teardown
if @serv
@serv.stop
@serv = nil
end
if @client
# @client.close
@client = nil
end
end
def conn
ensure_server_started
@client ||= Net::LDAP.new(host: HOST, port: PORT)
end
def test_bind2
pend("net-ldap gem doesn't support protocol 2")
# TODO: Net::LDAP only supports protocol 3
conn.set_option(LDAP::LDAP_OPT_PROTOCOL_VERSION, 2)
conn.auth("foo","bar")
conn.bind
assert_equal([:simple_bind, 2, "foo", "bar"], MockOperation.lastop)
# cannot bind any more; ldap client library says "already binded." (sic)
end
def test_bind3
conn.auth("foo","bar")
conn.bind
assert_equal([:simple_bind, 3, "foo", "bar"], MockOperation.lastop)
# cannot bind any more; ldap client library says "already binded." (sic)
end
def test_add
entry1 = {
objectclass: ['top', 'domain'],
o: ['TTSKY.NET'],
dc: ['localhost'],
}
conn.add(dn: "dc=localhost, dc=domain", attributes: entry1)
assert_equal([:add, "dc=localhost, dc=domain", {
'objectclass'=>['top', 'domain'],
'o'=>['TTSKY.NET'],
'dc'=>['localhost'],
}], MockOperation.lastop)
entry2 = {
objectclass: ['top', 'person'],
cn: ['Takaaki Tateishi'],
sn: ['ttate','Tateishi', "zero\000zero"],
}
conn.add(dn: "cn=Takaaki Tateishi, dc=localhost, dc=localdomain", attributes: entry2)
assert_equal([:add, "cn=Takaaki Tateishi, dc=localhost, dc=localdomain", {
'objectclass'=>['top', 'person'],
'cn'=>['Takaaki Tateishi'],
'sn'=>['ttate','Tateishi',"zero\000zero"],
}], MockOperation.lastop)
end
def test_del
conn.delete(dn: "cn=Takaaki-Tateishi, dc=localhost, dc=localdomain")
assert_equal([:del, "cn=Takaaki-Tateishi, dc=localhost, dc=localdomain"], MockOperation.lastop)
end
def test_compare
pend("net-ldap gem doesn't support compare requests")
res = conn.compare("cn=Takaaki Tateishi, dc=localhost, dc=localdomain",
"cn", "Takaaki Tateishi")
assert_equal([:compare, "cn=Takaaki Tateishi, dc=localhost, dc=localdomain",
"cn", "Takaaki Tateishi"], MockOperation.lastop)
assert res
res = conn.compare("cn=Takaaki Tateishi, dc=localhost, dc=localdomain",
"cn", "false")
assert_equal([:compare, "cn=Takaaki Tateishi, dc=localhost, dc=localdomain",
"cn", "false"], MockOperation.lastop)
refute res
end
def test_modrdn
conn.modify_rdn(olddn: "cn=Takaaki Tateishi, dc=localhost, dc=localdomain",
newrdn: "cn=Takaaki-Tateishi",
delete_attributes: true)
assert_equal([:modifydn, "cn=Takaaki Tateishi, dc=localhost, dc=localdomain",
"cn=Takaaki-Tateishi", true, nil], MockOperation.lastop)
# FIXME: ruby-ldap doesn't support the four-argument form
end
def test_modify
entry = [
[:add, :objectclass, ['top', 'domain']],
[:delete, :o, []],
[:replace, :dc, ['localhost']],
]
conn.modify(dn: "dc=localhost, dc=domain", operations: entry)
assert_equal([:modify, "dc=localhost, dc=domain", {
'objectclass' => [:add, 'top', 'domain'],
'o' => [:delete],
'dc' => [:replace, 'localhost'],
}], MockOperation.lastop)
end
def test_search
res = []
conn.search(base: "dc=localhost, dc=localdomain",
scope: Net::LDAP::SearchScope_WholeSubtree,
filter: "(objectclass=*)") do |e|
res << e.to_h
end
assert_equal([:search, "dc=localhost, dc=localdomain",
LDAP::Server::WholeSubtree,
LDAP::Server::NeverDerefAliases,
[:true], []], MockOperation.lastop)
exp = [
{a: ["1","2"], b: ["boing"], dn: ["cn=foo"]},
{a: ["3","4","5"], b: ["wibble"], dn: ["cn=bar"]},
]
assert_equal exp, res
res = []
# FIXME: ruby-ldap doesn't seem to allow DEREF options to be set
conn.search(base: "dc=localhost, dc=localdomain",
scope: Net::LDAP::SearchScope_BaseObject,
filter: "(&(cn=foo)(objectclass=*)(|(!(sn=*))(ou>=baz)(o<=z)(cn=*and*er)))",
attributes: [:a, :b]) do |e|
res << e.to_h
end
assert_equal([:search, "dc=localhost, dc=localdomain",
LDAP::Server::BaseObject,
LDAP::Server::NeverDerefAliases,
[:and, [:eq, "cn", nil, "foo"],
[:or, [:not, [:present, "sn"]],
[:ge, "ou", nil, "baz"],
[:le, "o", nil, "z"],
[:substrings, "cn", nil, nil, "and", "er"],
],
], ["a","b"]], MockOperation.lastop)
assert_equal exp, res
end
def test_search_with_range
res = []
conn.search(base: "dc=localhost, dc=localdomain",
scope: Net::LDAP::SearchScope_BaseObject,
attributes: ["a;range=1-2", "b"]) do |e|
res << e.to_h
end
assert_equal([:search, "dc=localhost, dc=localdomain",
LDAP::Server::BaseObject,
LDAP::Server::NeverDerefAliases,
[:true], ["a","b"]], MockOperation.lastop)
exp = [
{a: [], "a;range=1-*": ["2"], b: ["boing"], dn: ["cn=foo"]},
{a: [], "a;range=1-2": ["4","5"], b: ["wibble"], dn: ["cn=bar"]},
]
assert_equal exp, res
end
def test_search_with_range_limit
start_server(attribute_range_limit: 2)
res = []
conn.search(base: "dc=localhost, dc=localdomain",
scope: Net::LDAP::SearchScope_WholeSubtree,
filter: "(objectclass=*)") do |e|
res << e.to_h
end
assert_equal([:search, "dc=localhost, dc=localdomain",
LDAP::Server::WholeSubtree,
LDAP::Server::NeverDerefAliases,
[:true], []], MockOperation.lastop)
exp = [
{a: ["1","2"], b: ["boing"], dn: ["cn=foo"]},
{a: [], "a;range=0-1": ["3","4"], b: ["wibble"], dn: ["cn=bar"]},
]
assert_equal exp, res
end
end