ruby-ldapserver 0.5.3 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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��ѕ�