ruby-ldapserver 0.5.3 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -12,7 +12,7 @@ Thread.abort_on_exception = true
12
12
  require 'ldap/server/operation'
13
13
  require 'ldap/server/server'
14
14
 
15
- require 'ldap'
15
+ require 'net/ldap'
16
16
 
17
17
  # We subclass the Operation class, overriding the methods to do what we need
18
18
 
@@ -23,11 +23,11 @@ class MockOperation < LDAP::Server::Operation
23
23
  end
24
24
 
25
25
  def simple_bind(version, user, pass)
26
- @@lastop = [:simple_bind, version, user, pass]
26
+ @@lastop = [:simple_bind, version.to_i, user, pass]
27
27
  end
28
28
 
29
29
  def search(basedn, scope, deref, filter)
30
- @@lastop = [:search, basedn, scope, deref, filter, @attributes]
30
+ @@lastop = [:search, basedn, scope.to_i, deref.to_i, filter, @attributes]
31
31
  send_SearchResultEntry("cn=foo", {"a"=>["1","2"], "b"=>"boing"})
32
32
  send_SearchResultEntry("cn=bar", {"a"=>["3","4","5"], "b"=>"wibble"})
33
33
  end
@@ -62,209 +62,94 @@ class TestLdap < Test::Unit::TestCase
62
62
  HOST = '127.0.0.1'
63
63
  PORT = 1389
64
64
 
65
- def open_child_posix
66
- IO.popen("-","w+").tap do |io|
67
- unless io
68
- do_child Kernel, Kernel
69
- exit!
70
- end
71
- end
72
- end
73
-
74
- class DoubleIO < IO
75
- def initialize out, inio
76
- @out_io = out
77
- @in_io = inio
78
- end
79
-
80
- def read *a
81
- @out_io.read *a
82
- end
83
-
84
- def write *a
85
- @in_io.write *a
86
- end
87
-
88
- def gets
89
- @out_io.gets
90
- end
91
-
92
- def close
93
- @in_io.close
94
- @out_io.close
95
- end
96
- end
97
-
98
- def open_child_java
99
- in_rd, in_wr = IO.pipe
100
- out_rd, out_wr = IO.pipe
65
+ def start_client
66
+ in_ = Queue.new
67
+ out = Queue.new
101
68
  Thread.new do
102
- do_child in_rd, out_wr
69
+ do_child(in_, out)
103
70
  end
104
- DoubleIO.new(out_rd, in_wr)
71
+ return in_, out
105
72
  end
106
73
 
107
- def open_child
108
- case RUBY_PLATFORM
109
- when 'java'
110
- open_child_java
111
- else
112
- open_child_posix
113
- end
74
+ def ensure_server_started
75
+ @serv || start_server
114
76
  end
115
77
 
116
- def setup
117
- @ppid = $$
118
- @io = open_child
119
-
78
+ def start_server(opts={})
120
79
  # back to a single process (the parent). Now we start our
121
80
  # listener thread
122
- @serv = LDAP::Server.new(
123
- :bindaddr => '127.0.0.1',
124
- :port => PORT,
125
- :nodelay => true,
126
- :operation_class => MockOperation
127
- )
81
+ @serv = LDAP::Server.new({
82
+ :bindaddr => '127.0.0.1',
83
+ :port => PORT,
84
+ :nodelay => true,
85
+ :operation_class => MockOperation,
86
+ }.merge(opts))
87
+
128
88
  @serv.run_tcpserver
129
89
  end
130
90
 
91
+ def setup
92
+ @client = nil
93
+ @serv = nil
94
+ end
95
+
131
96
  def teardown
132
97
  if @serv
133
98
  @serv.stop
134
99
  @serv = nil
135
100
  end
136
- if @io
137
- @io.puts "quit"
138
- @io.gets
139
- @io.close
140
- @io = nil
141
- end
142
- end
143
-
144
- # Process commands on stdin in child
145
-
146
- def do_child in_, out
147
- while true
148
- begin
149
- a = in_.gets.chomp
150
- conn ||= LDAP::Conn.new(HOST,PORT)
151
- case a
152
- when "bind2"
153
- conn.set_option(LDAP::LDAP_OPT_PROTOCOL_VERSION, 2)
154
- conn.bind("foo","bar")
155
- when "bind3"
156
- conn.set_option(LDAP::LDAP_OPT_PROTOCOL_VERSION, 3)
157
- conn.bind("foo","bar")
158
- # these examples taken from the ruby-ldap examples
159
- when "add1"
160
- entry1 = [
161
- LDAP.mod(LDAP::LDAP_MOD_ADD, 'objectclass', ['top', 'domain']),
162
- LDAP.mod(LDAP::LDAP_MOD_ADD, 'o', ['TTSKY.NET']),
163
- LDAP.mod(LDAP::LDAP_MOD_ADD, 'dc', ['localhost']),
164
- ]
165
- conn.add("dc=localhost, dc=domain", entry1)
166
- when "add2"
167
- entry2 = [
168
- LDAP.mod(LDAP::LDAP_MOD_ADD, 'objectclass', ['top', 'person']),
169
- LDAP.mod(LDAP::LDAP_MOD_ADD, 'cn', ['Takaaki Tateishi']),
170
- LDAP.mod(LDAP::LDAP_MOD_ADD | LDAP::LDAP_MOD_BVALUES, 'sn', ['ttate','Tateishi', "zero\000zero"]),
171
- ]
172
- conn.add("cn=Takaaki Tateishi, dc=localhost, dc=localdomain", entry2)
173
- when "del"
174
- conn.delete("cn=Takaaki-Tateishi, dc=localhost, dc=localdomain")
175
- when /^compare (.*)/
176
- begin
177
- case conn.compare("cn=Takaaki Tateishi, dc=localhost, dc=localdomain",
178
- "cn", $1)
179
- when true; out.puts "OK true"; next
180
- when false; out.puts "OK false"; next
181
- end
182
- rescue LDAP::ResultError => e
183
- # For older versions of ruby-ldap
184
- case e.message
185
- when /Compare True/i; out.puts "OK true"; next
186
- when /Compare False/i; out.puts "OK false"; next
187
- end
188
- raise
189
- end
190
- when "modrdn"
191
- conn.modrdn("cn=Takaaki Tateishi, dc=localhost, dc=localdomain",
192
- "cn=Takaaki-Tateishi",
193
- true)
194
- when "modify"
195
- entry = [
196
- LDAP.mod(LDAP::LDAP_MOD_ADD, 'objectclass', ['top', 'domain']),
197
- LDAP.mod(LDAP::LDAP_MOD_DELETE, 'o', []),
198
- LDAP.mod(LDAP::LDAP_MOD_REPLACE, 'dc', ['localhost']),
199
- ]
200
- conn.modify("dc=localhost, dc=domain", entry)
201
- when "search"
202
- res = {}
203
- conn.search("dc=localhost, dc=localdomain",
204
- LDAP::LDAP_SCOPE_SUBTREE,
205
- "(objectclass=*)") do |e|
206
- entry = e.to_hash
207
- dn = entry.delete("dn").first
208
- res[dn] = entry
209
- end
210
- exp = {
211
- "cn=foo" => {"a"=>["1","2"], "b"=>["boing"]},
212
- "cn=bar" => {"a"=>["3","4","5"], "b"=>["wibble"]},
213
- }
214
- if res != exp
215
- raise "Bad Search Result, expected\n#{exp.inspect}\ngot\n#{res.inspect}"
216
- end
217
- when "search2"
218
- # FIXME: ruby-ldap doesn't seem to allow DEREF options to be set
219
- conn.search("dc=localhost, dc=localdomain",
220
- LDAP::LDAP_SCOPE_BASE,
221
- "(&(cn=foo)(objectclass=*)(|(!(sn=*))(ou>=baz)(o<=z)(cn~=brian)(cn=*and*er)))",
222
- ["a","b"]) do |e|
223
- entry = e.to_hash
224
- dn = entry.delete("dn").first
225
- res[dn] = entry
226
- end
227
- when "quit"
228
- out.puts "OK"
229
- break
230
- else
231
- raise "Bad command! #{a.inspect}"
232
- end
233
- out.puts "OK"
234
- rescue Exception => e
235
- $stderr.puts "Child exception: #{e}\n\t#{e.backtrace.join("\n\t")}"
236
- out.puts "ERR #{e}"
237
- end
101
+ if @client
102
+ # @client.close
103
+ @client = nil
238
104
  end
239
105
  end
240
106
 
241
- def req(cmd)
242
- @io.puts cmd
243
- res = @io.gets.chomp
244
- assert_match(/^OK/, res)
245
- res
107
+ def conn
108
+ ensure_server_started
109
+ @client ||= Net::LDAP.new(host: HOST, port: PORT)
246
110
  end
247
111
 
248
112
  def test_bind2
249
- req("bind2")
113
+ pend("net-ldap gem doesn't support protocol 2")
114
+
115
+ # TODO: Net::LDAP only supports protocol 3
116
+ conn.set_option(LDAP::LDAP_OPT_PROTOCOL_VERSION, 2)
117
+ conn.auth("foo","bar")
118
+ conn.bind
119
+
250
120
  assert_equal([:simple_bind, 2, "foo", "bar"], MockOperation.lastop)
251
121
  # cannot bind any more; ldap client library says "already binded." (sic)
252
122
  end
253
123
 
254
124
  def test_bind3
255
- req("bind3")
125
+ conn.auth("foo","bar")
126
+ conn.bind
127
+
256
128
  assert_equal([:simple_bind, 3, "foo", "bar"], MockOperation.lastop)
257
129
  # cannot bind any more; ldap client library says "already binded." (sic)
258
130
  end
259
131
 
260
132
  def test_add
261
- req("add1")
133
+ entry1 = {
134
+ objectclass: ['top', 'domain'],
135
+ o: ['TTSKY.NET'],
136
+ dc: ['localhost'],
137
+ }
138
+ conn.add(dn: "dc=localhost, dc=domain", attributes: entry1)
139
+
262
140
  assert_equal([:add, "dc=localhost, dc=domain", {
263
141
  'objectclass'=>['top', 'domain'],
264
142
  'o'=>['TTSKY.NET'],
265
143
  'dc'=>['localhost'],
266
144
  }], MockOperation.lastop)
267
- req("add2")
145
+
146
+ entry2 = {
147
+ objectclass: ['top', 'person'],
148
+ cn: ['Takaaki Tateishi'],
149
+ sn: ['ttate','Tateishi', "zero\000zero"],
150
+ }
151
+ conn.add(dn: "cn=Takaaki Tateishi, dc=localhost, dc=localdomain", attributes: entry2)
152
+
268
153
  assert_equal([:add, "cn=Takaaki Tateishi, dc=localhost, dc=localdomain", {
269
154
  'objectclass'=>['top', 'person'],
270
155
  'cn'=>['Takaaki Tateishi'],
@@ -273,30 +158,44 @@ class TestLdap < Test::Unit::TestCase
273
158
  end
274
159
 
275
160
  def test_del
276
- req("del")
161
+ conn.delete(dn: "cn=Takaaki-Tateishi, dc=localhost, dc=localdomain")
277
162
  assert_equal([:del, "cn=Takaaki-Tateishi, dc=localhost, dc=localdomain"], MockOperation.lastop)
278
163
  end
279
164
 
280
165
  def test_compare
281
- r = req("compare Takaaki Tateishi")
282
- assert_match(/OK true/, r)
166
+ pend("net-ldap gem doesn't support compare requests")
167
+ res = conn.compare("cn=Takaaki Tateishi, dc=localhost, dc=localdomain",
168
+ "cn", "Takaaki Tateishi")
169
+
283
170
  assert_equal([:compare, "cn=Takaaki Tateishi, dc=localhost, dc=localdomain",
284
171
  "cn", "Takaaki Tateishi"], MockOperation.lastop)
285
- r = req("compare false")
286
- assert_match(/OK false/, r)
172
+ assert res
173
+
174
+ res = conn.compare("cn=Takaaki Tateishi, dc=localhost, dc=localdomain",
175
+ "cn", "false")
287
176
  assert_equal([:compare, "cn=Takaaki Tateishi, dc=localhost, dc=localdomain",
288
177
  "cn", "false"], MockOperation.lastop)
178
+ refute res
289
179
  end
290
180
 
291
181
  def test_modrdn
292
- req("modrdn")
182
+ conn.modify_rdn(olddn: "cn=Takaaki Tateishi, dc=localhost, dc=localdomain",
183
+ newrdn: "cn=Takaaki-Tateishi",
184
+ delete_attributes: true)
185
+
293
186
  assert_equal([:modifydn, "cn=Takaaki Tateishi, dc=localhost, dc=localdomain",
294
187
  "cn=Takaaki-Tateishi", true, nil], MockOperation.lastop)
295
188
  # FIXME: ruby-ldap doesn't support the four-argument form
296
189
  end
297
190
 
298
191
  def test_modify
299
- req("modify")
192
+ entry = [
193
+ [:add, :objectclass, ['top', 'domain']],
194
+ [:delete, :o, []],
195
+ [:replace, :dc, ['localhost']],
196
+ ]
197
+ conn.modify(dn: "dc=localhost, dc=domain", operations: entry)
198
+
300
199
  assert_equal([:modify, "dc=localhost, dc=domain", {
301
200
  'objectclass' => [:add, 'top', 'domain'],
302
201
  'o' => [:delete],
@@ -305,12 +204,33 @@ class TestLdap < Test::Unit::TestCase
305
204
  end
306
205
 
307
206
  def test_search
308
- req("search")
207
+ res = []
208
+ conn.search(base: "dc=localhost, dc=localdomain",
209
+ scope: Net::LDAP::SearchScope_WholeSubtree,
210
+ filter: "(objectclass=*)") do |e|
211
+ res << e.to_h
212
+ end
213
+
309
214
  assert_equal([:search, "dc=localhost, dc=localdomain",
310
215
  LDAP::Server::WholeSubtree,
311
216
  LDAP::Server::NeverDerefAliases,
312
217
  [:true], []], MockOperation.lastop)
313
- req("search2")
218
+
219
+ exp = [
220
+ {a: ["1","2"], b: ["boing"], dn: ["cn=foo"]},
221
+ {a: ["3","4","5"], b: ["wibble"], dn: ["cn=bar"]},
222
+ ]
223
+ assert_equal exp, res
224
+
225
+ res = []
226
+ # FIXME: ruby-ldap doesn't seem to allow DEREF options to be set
227
+ conn.search(base: "dc=localhost, dc=localdomain",
228
+ scope: Net::LDAP::SearchScope_BaseObject,
229
+ filter: "(&(cn=foo)(objectclass=*)(|(!(sn=*))(ou>=baz)(o<=z)(cn=*and*er)))",
230
+ attributes: [:a, :b]) do |e|
231
+ res << e.to_h
232
+ end
233
+
314
234
  assert_equal([:search, "dc=localhost, dc=localdomain",
315
235
  LDAP::Server::BaseObject,
316
236
  LDAP::Server::NeverDerefAliases,
@@ -318,9 +238,52 @@ class TestLdap < Test::Unit::TestCase
318
238
  [:or, [:not, [:present, "sn"]],
319
239
  [:ge, "ou", nil, "baz"],
320
240
  [:le, "o", nil, "z"],
321
- [:approx, "cn", nil, "brian"],
322
241
  [:substrings, "cn", nil, nil, "and", "er"],
323
242
  ],
324
243
  ], ["a","b"]], MockOperation.lastop)
244
+
245
+ assert_equal exp, res
246
+ end
247
+
248
+ def test_search_with_range
249
+ res = []
250
+ conn.search(base: "dc=localhost, dc=localdomain",
251
+ scope: Net::LDAP::SearchScope_BaseObject,
252
+ attributes: ["a;range=1-2", "b"]) do |e|
253
+ res << e.to_h
254
+ end
255
+
256
+ assert_equal([:search, "dc=localhost, dc=localdomain",
257
+ LDAP::Server::BaseObject,
258
+ LDAP::Server::NeverDerefAliases,
259
+ [:true], ["a","b"]], MockOperation.lastop)
260
+
261
+ exp = [
262
+ {a: [], "a;range=1-*": ["2"], b: ["boing"], dn: ["cn=foo"]},
263
+ {a: [], "a;range=1-2": ["4","5"], b: ["wibble"], dn: ["cn=bar"]},
264
+ ]
265
+ assert_equal exp, res
266
+ end
267
+
268
+ def test_search_with_range_limit
269
+ start_server(attribute_range_limit: 2)
270
+
271
+ res = []
272
+ conn.search(base: "dc=localhost, dc=localdomain",
273
+ scope: Net::LDAP::SearchScope_WholeSubtree,
274
+ filter: "(objectclass=*)") do |e|
275
+ res << e.to_h
276
+ end
277
+
278
+ assert_equal([:search, "dc=localhost, dc=localdomain",
279
+ LDAP::Server::WholeSubtree,
280
+ LDAP::Server::NeverDerefAliases,
281
+ [:true], []], MockOperation.lastop)
282
+
283
+ exp = [
284
+ {a: ["1","2"], b: ["boing"], dn: ["cn=foo"]},
285
+ {a: [], "a;range=0-1": ["3","4"], b: ["wibble"], dn: ["cn=bar"]},
286
+ ]
287
+ assert_equal exp, res
325
288
  end
326
289
  end
data/test/trie_test.rb ADDED
@@ -0,0 +1,60 @@
1
+ require File.dirname(__FILE__) + '/test_helper'
2
+ require 'ldap/server/trie'
3
+
4
+ class TestTrie < Test::Unit::TestCase
5
+
6
+ def test_trie_base
7
+ trie = LDAP::Server::Trie.new do |trie|
8
+ trie.insert 'ou=Users,dc=mydomain,dc=com,op=bind', 'UsersBindTree'
9
+ trie.insert 'ou=Users,dc=mydomain,dc=com,op=search', 'UsersSearchTree'
10
+ trie.insert 'ou=Groups,dc=mydomain,dc=com,op=search', 'GroupsSearchTree'
11
+ trie.insert 'dc=mydomain,dc=com,op=search', 'RootSearchValue'
12
+ trie.insert 'dc=com,op=search', ''
13
+ end
14
+
15
+ assert_equal trie.lookup('ou=Users,dc=mydomain,dc=com,op=bind'), 'UsersBindTree'
16
+ assert_equal trie.lookup('ou=Users,dc=mydomain,dc=com,op=search'), 'UsersSearchTree'
17
+ assert_equal trie.lookup('ou=Groups,dc=mydomain,dc=com,op=search'), 'GroupsSearchTree'
18
+ assert_equal trie.lookup('dc=mydomain,dc=com,op=search'), 'RootSearchValue'
19
+ assert_equal trie.lookup('dc=com,op=search'), ''
20
+ assert_nil trie.lookup 'dc=mydomain,dc=com,op=bind'
21
+ assert_nil trie.lookup nil
22
+
23
+ assert_raises LDAP::Server::Trie::NodeNotFoundError do
24
+ trie.lookup 'ou=DoesNotExist,dc=mydomain,dc=com,op=search'
25
+ end
26
+ end
27
+
28
+ def test_trie_wildcard
29
+ trie = LDAP::Server::Trie.new do |trie|
30
+ trie.insert 'uid=:uid,ou=Users,dc=mydomain,dc=com', 'SpecificUsers'
31
+ trie.insert 'ou=Users,dc=mydomain,dc=com', 'Users'
32
+ trie.insert 'ou=Users,dc=:domain,dc=:tld', 'Domain'
33
+ end
34
+
35
+ assert_equal trie.lookup('uid=john,ou=Users,dc=mydomain,dc=com'), 'SpecificUsers'
36
+ assert_equal trie.lookup('uid=jane,ou=Users,dc=mydomain,dc=com'), 'SpecificUsers'
37
+ assert_equal trie.lookup('ou=Users,dc=mydomain,dc=com'), 'Users'
38
+ assert_equal trie.lookup('ou=Users,dc=otherdomain,dc=net'), 'Domain'
39
+ end
40
+
41
+ def test_trie_match
42
+ trie = LDAP::Server::Trie.new do |trie|
43
+ trie.insert 'uid=:uid,ou=Users,dc=mydomain,dc=com', 'SpecificUsers'
44
+ trie.insert 'ou=Users,dc=mydomain,dc=com', 'Users'
45
+ trie.insert 'dc=mydomain,dc=com', 'Domains'
46
+ end
47
+
48
+ assert_equal trie.match('uid=john,ou=Users,dc=mydomain,dc=com'),
49
+ ['uid=:uid,ou=Users,dc=mydomain,dc=com', 'SpecificUsers']
50
+ assert_equal trie.match('cn=john,ou=Users,dc=mydomain,dc=com'),
51
+ ['ou=Users,dc=mydomain,dc=com', 'Users']
52
+ assert_equal trie.match('ou=Users,dc=mydomain,dc=com'),
53
+ ['ou=Users,dc=mydomain,dc=com', 'Users']
54
+ assert_equal trie.match('dc=mydomain,dc=com'),
55
+ ['dc=mydomain,dc=com', 'Domains']
56
+ assert_equal trie.match('dc=otherdomain,dc=com'),
57
+ [nil, nil]
58
+ end
59
+
60
+ end
data.tar.gz.sig ADDED
@@ -0,0 +1,2 @@
1
+ �n�ls�S�~�ɥ]��+,�h^��<��G�$��Q`��&}V�b<���R*ĢA�3yP���y��㝳�iI]��?�Z��,&�G�
2
+ (��R����ۃtD���q�M*,��Q��Vǟu.IMtzJ-����u�K��jzd��~�%ŕr6h.�� �Z��ѕ�