ldapmapper 1.0.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.
Files changed (3) hide show
  1. data/lib/ldapmapper.rb +522 -0
  2. data/test/testldapmapper.rb +11 -0
  3. metadata +46 -0
data/lib/ldapmapper.rb ADDED
@@ -0,0 +1,522 @@
1
+ #!/Usr/bin/env ruby
2
+ #
3
+ # = LdapMapper : LDAP CRUD Object
4
+ #
5
+ # == Copyright Ultragreen (c) 2005
6
+ #
7
+ # == About :
8
+ #
9
+ # * Author:: Romain GEORGES
10
+ # * type:: class definition Ruby
11
+ # * obj:: Generic LDAP class
12
+ # * CVS Version:: $Id: ldapmapper.rb,v 1.1.1.1 2006/09/09 10:57:45 lecid Exp $
13
+ #
14
+ # == Exemples :
15
+ #
16
+ # #!/usr/local/bin/ruby
17
+ # require 'rubygems'
18
+ # require_gem 'ldapmapper'
19
+ # include Ldapmapper
20
+ # _basedn = 'dc=__domaine__,dc=__tld__'
21
+ # _dn = "ou=toto,#{_basedn}"
22
+ # record = LdapMapper.new(_dn,'__secret__',"cn=root,#{_basedn}")
23
+ # puts "- Could create it ? : #{record.can_create?}"
24
+ # puts "- Already exist ? : #{record.exist?}"
25
+ # puts "- Is it a node ? : #{record.is_node?}"
26
+ # puts "- Is it the base ? : #{record.is_base?}"
27
+ # if record.exist? then
28
+ # puts "- ObjectClasses list :"
29
+ # record.list_objectclass.each{|objectclass|
30
+ # puts " * #{objectclass}"
31
+ # }
32
+ # puts "- Attributes list : "
33
+ # record.list_attributs.each{|attribute,value|
34
+ # if value.size > 1 then
35
+ # puts "* #{attribute} ="
36
+ # value.each{|val| puts " - #{val}"
37
+ # }
38
+ # else
39
+ # puts "* #{attribute} = #{value}"
40
+ # end
41
+ # }
42
+ # puts record.description
43
+ # record.description = `date`
44
+ # record.commit!
45
+ # elsif record.can_create?
46
+ # record.add_objectclass!('organizationalUnit')
47
+ # record.ou = 'toto'
48
+ # record.description = "Test"
49
+ # p record.must
50
+ # p record.may
51
+ # record.commit!
52
+ # else
53
+ # puts "kaboum!"
54
+ # end
55
+ #
56
+ # <b>first running :</b>
57
+ #
58
+ # - Could create it ? : true
59
+ # - Already exist ? : false
60
+ # - Is it a node ? : false
61
+ # - Is it the base ? : false
62
+ # ["ou", "objectClass", "dn"]
63
+ # ["physicalDeliveryOfficeName", "l", "st", "telexNumber", "destinationIndicator", "businessCategory",
64
+ # "postalAddress", "telephoneNumber", "searchGuide", "internationaliSDNNumber", "preferredDeliveryMethod",
65
+ # "description", "postalCode", "teletexTerminalIdentifier", "userPassword", "street",
66
+ # "registeredAddress", "postOfficeBox", "facsimileTelephoneNumber", "seeAlso", "x121Address"]
67
+ #
68
+ # <b>second ruuning :</b>
69
+ #
70
+ # - Could create it ? : false
71
+ # - Already exist ? : true
72
+ # - Is it a node ? : false
73
+ # - Is it the base ? : false
74
+ # - ObjectClasses list :
75
+ # * top
76
+ # * organizationalUnit
77
+ # - Attributes list :
78
+ # * description = Jeu 7 sep 2006 16:11:44 CEST
79
+ # * ou = toto
80
+ # * objectClass =
81
+ # - top
82
+ # - organizationalUnit
83
+ # * dn = ou=toto,dc=ultragreen,dc=net
84
+ # Jeu 7 sep 2006 16:11:44 CEST
85
+
86
+
87
+ # require the LDAP's scheme and LDAP librairies
88
+ require 'ldap'
89
+ require "ldap/schema"
90
+
91
+
92
+ # General module for LDAP CRUD Ojects
93
+ module Ldapmapper
94
+
95
+ # identity lib
96
+ # version of the library
97
+ LIB_VERSION='1.0.0'
98
+ # name of the author
99
+ AUTHOR='Romain GEORGES'
100
+ # date of creation
101
+ DATE='30/07/2005'
102
+ # valuable observations
103
+ OBS='Generic LDAP class'
104
+
105
+ # generic class for LDAP object
106
+ class LdapTemplate
107
+
108
+ # attributs for LDAP connection
109
+
110
+ # hostname of the LDAP server
111
+ attr_accessor :host_ldap
112
+ # TCP/IP port of the LDAP server
113
+ attr_accessor :port_ldap
114
+ # LDAP scope for search
115
+ attr_accessor :scope_ldap
116
+ # current filter for search
117
+ attr_accessor :filter_ldap
118
+ # LDAP base DN for the instance
119
+ attr_accessor :basedn_ldap
120
+ # credential for the instance
121
+ attr_accessor :passdn_ldap
122
+ # LDAP rootdn for LDAP
123
+ attr_accessor :rootdn_ldap
124
+
125
+ # constructor for LdapTemplate
126
+ #
127
+ # _passdn is required, _rootdn, _host, _filter, _port and _scope are optionals
128
+ #
129
+ # return a boolean
130
+ def initialize(_passdn,_rootdn='cn=root',_host='localhost', _filter='(objectClass=*)', _port=389, _scope=LDAP::LDAP_SCOPE_SUBTREE)
131
+ @host_ldap = _host # default localhost
132
+ @port_ldap = _port # default 389
133
+ @scope_ldap = _scope # default to SUBTREE
134
+ @filter_ldap = _filter # default (objectClass=*)
135
+ @basedn_ldap = get_basedn(_host,_port)
136
+ @passdn_ldap = _passdn # no default
137
+ @rootdn_ldap = _rootdn # default cn=root
138
+ return true
139
+ end
140
+
141
+ end
142
+
143
+ # Mapping LDAP object class
144
+ #
145
+ # This is the real CRUD Class
146
+ #
147
+ # contructor arguments :
148
+ #
149
+ # _dn and _passdn are required, _rootdn, _host and _port are optionals
150
+ class LdapMapper < LdapTemplate
151
+
152
+ # DN binding point attribut
153
+ attr_accessor :dn_ldap
154
+ # Hash of attributes with optional or mandatory aspects in value
155
+ attr_accessor :list_attributs_type
156
+ # Array of objectclass for the current record
157
+ attr_accessor :list_objectclass
158
+ # Hash of attributes in LDIF mapping, value should be an array in case of multivalue data
159
+ attr_accessor :list_attributs
160
+
161
+ # constructor with dn_ldap initialisation
162
+ #
163
+ # _dn and _passdn are required, _rootdn, _host and _port are optionals
164
+ #
165
+ # return a boolean
166
+ def initialize(_dn,_passdn, _rootdn='cn=root',_host = 'localhost', _port = 389)
167
+ _scope = LDAP::LDAP_SCOPE_SUBTREE
168
+ _filter = '(objectClass=*)'
169
+ super(_passdn, _rootdn, _host, _filter, _port, _scope )
170
+ @dn_ldap = _dn
171
+ @list_objectclass = Array::new
172
+ @list_attributs_type = Hash::new
173
+ @list_attributs = Hash::new
174
+ add_objectclass!
175
+ end
176
+
177
+ # add an objectclass in the list and map attribut
178
+ #
179
+ # _objectclass is optional
180
+ #
181
+ # return an Hash
182
+ def add_objectclass!(_objectclass = 'top')
183
+ @list_objectclass = @list_objectclass.concat(get_objectclass_list(self.dn_ldap,self.host_ldap,self.port_ldap))
184
+ @list_objectclass.push(_objectclass).uniq!
185
+ @list_attributs_type = get_attributs_list(self.list_objectclass,self.host_ldap,self.port_ldap)
186
+ @list_attributs = map_record(self.dn_ldap,self.host_ldap,self.port_ldap)
187
+ if not @list_attributs.nil? then
188
+ @list_attributs.each{|_key,_value|
189
+ @list_attributs_type.each{|_attr,_trash|
190
+ if self.get_alias(_key).include?(_attr)
191
+ @list_attributs.delete(_key)
192
+ @list_attributs[_attr] = _value
193
+ end
194
+ }
195
+ }
196
+ end
197
+ @list_attributs["objectClass"] = @list_objectclass
198
+ @list_attributs_type.each_key {|_key|
199
+ eval("
200
+ def #{_key.downcase}
201
+ return @list_attributs['#{_key}']
202
+ end
203
+ def #{_key.downcase}=(_value)
204
+ @list_attributs['#{_key}'] = _value
205
+ end
206
+ ")
207
+ }
208
+ end
209
+
210
+ # existance of an LDAP instance test method
211
+ #
212
+ # return a boolean
213
+ def exist?
214
+ if list_arbitrary_node(self.dn_ldap,self.host_ldap,self.port_ldap).empty? then
215
+ return false
216
+ else
217
+ return true
218
+ end
219
+ end
220
+
221
+ # test methode for LDAP instance situation node or termination
222
+ #
223
+ # return a boolean
224
+ def is_node?
225
+ if list_arbitrary_node(self.dn_ldap,self.host_ldap,self.port_ldap).length > 1 then
226
+ return true
227
+ else
228
+ return false
229
+ end
230
+ end
231
+
232
+ # test methode to check the ability to create the instance, already exist or not bindable
233
+ #
234
+ # return a boolean
235
+ def can_create?
236
+ return false if self.is_base?
237
+ if list_arbitrary_node(self.get_previous,self.host_ldap,self.port_ldap).length >= 1 and not self.exist? then
238
+ return true
239
+ else
240
+ return false
241
+ end
242
+ end
243
+
244
+ # return true if the dn to search is the basedn of the tree
245
+ #
246
+ # return a boolean
247
+ def is_base?
248
+ if self.dn_ldap == self.basedn_ldap then
249
+ return true
250
+ else
251
+ return false
252
+ end
253
+ end
254
+
255
+ # return the list of the attributes how must be present for add a record
256
+ #
257
+ # return an Array
258
+ def must
259
+ _must_list = Array::new
260
+ self.list_attributs_type.each{|_key,_value|
261
+ _must_list.push(_key) if _value == 'MUST'
262
+ }
263
+ _must_list.delete('dn') if _must_list.include?('dn')
264
+ return _must_list.delete('dn')
265
+ end
266
+
267
+ # return the attributes list how may be present in the record
268
+ #
269
+ # return an Array
270
+ def may
271
+ _must_list = Array::new
272
+ self.list_attributs_type.each{|_key,_value|
273
+ _must_list.push(_key) if _value == 'MAY'
274
+ }
275
+ return _must_list
276
+ end
277
+
278
+ # return true if the must attributes is completed in record before commit!
279
+ #
280
+ # return a boolean
281
+ def valid?
282
+ _result = true
283
+ self.must.each{|attribute|
284
+ _result = false if not self.list_attributs.include?(attribute)
285
+ }
286
+ return _result
287
+ end
288
+
289
+ # get the previous record if exist and if the record is not the basedn
290
+ #
291
+ # return a String
292
+ def get_previous
293
+ _rec_res = String::new('')
294
+ if not self.is_base? then
295
+ _rdn = String::new('')
296
+ _dn_table = Array::new
297
+ _rdn,*_dn_table = self.dn_ldap.split(',')
298
+ _rec_res = _dn_table.join(',')
299
+ end
300
+ return _rec_res
301
+ end
302
+
303
+ # method to list dn after the node in the the LDAP tree for the first level,
304
+ #
305
+ # return an Array
306
+ def list_node
307
+ _my_res = Array::new
308
+ _my_res = list_arbitrary_node(self.dn_ldap,self.host_ldap,self.port_ldap,LDAP::LDAP_SCOPE_ONELEVEL)
309
+ _my_res.delete(self.dn_ldap) if _my_res.include?(self.dn_ldap)
310
+ return _my_res
311
+ end
312
+
313
+ # commit the modification or the adding of the object in LDAP server
314
+ #
315
+ # return a boolean
316
+ def commit!
317
+ if self.exist? and self.valid? then
318
+ # case modifying an LDAP object
319
+ mod_object(self.dn_ldap, self.list_attributs, self.rootdn_ldap, self.basedn_ldap, self.passdn_ldap, self.host_ldap, self.port_ldap)
320
+ return true
321
+ elsif self.can_create? and self.valid? then
322
+ # case creating new object
323
+ add_object(self.dn_ldap, self.list_attributs, self.rootdn_ldap, self.basedn_ldap, self.passdn_ldap, self.host_ldap, self.port_ldap)
324
+ return true
325
+ else
326
+ return false
327
+ # case can't commit
328
+ end
329
+ end
330
+
331
+ end
332
+
333
+
334
+ # global method that list objectclass for a speficique dn
335
+ #
336
+ # server free methode
337
+ #
338
+ # _dn is required, _host, _port, _scope and _filter are optionals
339
+ #
340
+ # return an Array
341
+ def get_objectclass_list(_dn,_host='localhost',_port=389,_scope=LDAP::LDAP_SCOPE_BASE,_filter='(objectClass=*)')
342
+ _table_res = Array::new
343
+ begin
344
+ _conn = LDAP::Conn.new(_host,_port)
345
+ _conn.set_option(LDAP::LDAP_OPT_PROTOCOL_VERSION, 3)
346
+ _conn.bind {
347
+ _conn.search(_dn,_scope,_filter){|_e|
348
+ _table_res = _e.to_hash()['objectClass']
349
+ }
350
+ }
351
+ ensure
352
+ return _table_res
353
+ end
354
+ end
355
+
356
+ # get the base dn of an LDAP tree
357
+ #
358
+ # _host and _port are optionals
359
+ #
360
+ # return a String
361
+ def get_basedn(_host='localhost',_port=389)
362
+ _my_basedn = String::new('')
363
+ begin
364
+ _conn = LDAP::Conn.new(_host,_port)
365
+ _conn.set_option(LDAP::LDAP_OPT_PROTOCOL_VERSION, 3)
366
+ _conn.bind {
367
+ _my_basedn = _conn.root_dse[0]["namingContexts"].to_s
368
+ }
369
+ ensure
370
+ return _my_basedn
371
+ end
372
+ end
373
+
374
+ # get the alias list of an attribute in Schema
375
+ #
376
+ # _attribute is required, _host and _port are optionals
377
+ #
378
+ # return an Array
379
+ def get_alias(_attribute,_host='localhost',_port=389)
380
+ _my_list_attributs = Array::new
381
+ begin
382
+ _conn = LDAP::Conn.new(_host, _port)
383
+ _conn.bind{
384
+ _schema = _conn.schema()
385
+ _my_list_attributs = _schema.alias(_attribute)
386
+ }
387
+
388
+ ensure
389
+ return _my_list_attributs
390
+ end
391
+ end
392
+
393
+ # global method that list dn after the precised dn in the LDAP tree
394
+ #
395
+ # server free methode
396
+ #
397
+ # _dn id required, _host, _port, _scope, _filter are optionals
398
+ #
399
+ # return an Array
400
+ def list_arbitrary_node(_dn,_host=localhost,_port=389,_scope=LDAP::LDAP_SCOPE_SUBTREE,_filter='(objectClass=*)')
401
+ _table_res = Array::new
402
+ begin
403
+ _conn = LDAP::Conn.new(_host,_port)
404
+ _conn.set_option(LDAP::LDAP_OPT_PROTOCOL_VERSION, 3)
405
+ _conn.bind {
406
+ _conn.search(_dn,_scope,_filter){|_e|
407
+ _table_res.push(_e.dn)
408
+ }
409
+ }
410
+ ensure
411
+ return _table_res
412
+ end
413
+
414
+ end
415
+
416
+ # get the attributs list of an objectclass list
417
+ #
418
+ # server free method
419
+ #
420
+ # _list_objectclass is required, _host and _port are optionals
421
+ #
422
+ # return an Hash
423
+ def get_attributs_list(_list_objectclass,_host='localhost',_port=389)
424
+ _my_list_attributs = Hash::new
425
+ begin
426
+ _conn = LDAP::Conn.new(_host, _port)
427
+ _conn.bind{
428
+ _schema = _conn.schema()
429
+ _list_objectclass.each{|objectclass|
430
+ if objectclass != 'top' then
431
+ _schema.must(objectclass).each{|attributs| _my_list_attributs[attributs] = 'MUST'}
432
+ _schema.may(objectclass).each{|attributs| _my_list_attributs[attributs] = 'MAY'}
433
+ end
434
+ }
435
+ }
436
+ ensure
437
+ _my_list_attributs["dn"] = "MUST"
438
+ _my_list_attributs["objectClass"] = "MUST"
439
+ return _my_list_attributs
440
+ end
441
+ end
442
+
443
+ # map the attributs of class at run time for the current LDAP Object at precise DN
444
+ #
445
+ # _dn is required, _host, _port, _scope and _filter are optionals
446
+ #
447
+ # return an Hash
448
+ def map_record(_dn,_host='localhost',_port=389,_scope=LDAP::LDAP_SCOPE_SUBTREE,_filter='(objectClass=*)')
449
+ begin
450
+ _conn = LDAP::Conn.new(_host,_port)
451
+ _conn.set_option(LDAP::LDAP_OPT_PROTOCOL_VERSION, 3)
452
+ _conn.bind {
453
+ _conn.search(_dn,_scope,_filter){|_e|
454
+ return _e.to_hash()
455
+ }
456
+ }
457
+ rescue
458
+ return Hash::new
459
+ end
460
+ end
461
+
462
+ # add an ldap object
463
+ #
464
+ # _dn, _record, _rootdn, _basedn and _passdn are required, _host and _port are optional
465
+ #
466
+ # return a boolean
467
+ def add_object(_dn, _record, _rootdn, _basedn, _passdn, _host='localhost',_port=389)
468
+ _conn = LDAP::Conn.new(_host, _port)
469
+ _conn.set_option(LDAP::LDAP_OPT_PROTOCOL_VERSION, 3)
470
+ _record.delete('dn')
471
+ _conn.bind("#{_rootdn}", "#{_passdn}"){
472
+ begin
473
+ _data = self.list_attributs
474
+ _data.each{|_key,_value|
475
+ _data[_key] = _value.to_a
476
+ }
477
+ _conn.add("#{_dn}", _data)
478
+ return true
479
+ rescue LDAP::ResultError
480
+ return false
481
+ end
482
+ }
483
+ end
484
+
485
+ # modify an ldap object
486
+ #
487
+ # _dn, _record, _rootdn, _basedn and _passdn are required, _host and _port are optional
488
+ #
489
+ # return a boolean
490
+ def mod_object(_dn, _record, _rootdn, _basedn, _passdn, _host='localhost',_port=389)
491
+ _conn = LDAP::Conn.new(_host, _port)
492
+ _conn.set_option(LDAP::LDAP_OPT_PROTOCOL_VERSION, 3)
493
+ _record.delete('dn')
494
+ _conn.bind("#{_rootdn}", "#{_passdn}"){
495
+ begin
496
+ _conn.delete("#{_dn}")
497
+ _data = self.list_attributs
498
+ _data.each{|_key,_value|
499
+ _data[_key] = _value.to_a
500
+ }
501
+ _conn.add("#{_dn}", _data)
502
+ return true
503
+ rescue LDAP::ResultError
504
+ return false
505
+ end
506
+ }
507
+ end
508
+
509
+ # run description of the library in interactive mode
510
+ if $0 == __FILE__ then
511
+ puts "#{File::basename(__FILE__)}:"
512
+ puts 'this is a RUBY library file'
513
+ puts "Copyright (c) Ultragreen"
514
+ puts "Version : #{LIB_VERSION}"
515
+ puts "Author : #{AUTHOR}"
516
+ puts "Date release : #{DATE}"
517
+ puts "Observation : #{OBS}"
518
+ end
519
+
520
+ end
521
+
522
+ #==END==#
@@ -0,0 +1,11 @@
1
+ #!/usr/local/bin/ruby
2
+
3
+ require "ldapmapper"
4
+ require 'test/unit'
5
+
6
+ class TestLdapMapper < Test::Unit::TestCase
7
+
8
+ def test_simple
9
+ assert_equal(true,LdapMapper.new('ou=fetchmail,ou=mail,dc=ultragreen,dc=net','cn=root,dc=ultragreen,dc=net','l7isg00d').exist?)
10
+ end
11
+ end
metadata ADDED
@@ -0,0 +1,46 @@
1
+ --- !ruby/object:Gem::Specification
2
+ rubygems_version: 0.8.11
3
+ specification_version: 1
4
+ name: ldapmapper
5
+ version: !ruby/object:Gem::Version
6
+ version: 1.0.0
7
+ date: 2006-09-08 00:00:00 +02:00
8
+ summary: "Ldapmapper : CRUD Objects for LDAP mapping"
9
+ require_paths:
10
+ - lib
11
+ email: romain@ultragreen.net
12
+ homepage: http://www.ultragreen.net
13
+ rubyforge_project:
14
+ description: "Ldapmapper : provide CRUD object for LDAP data manipulations"
15
+ autorequire:
16
+ default_executable:
17
+ bindir:
18
+ has_rdoc: true
19
+ required_ruby_version: !ruby/object:Gem::Version::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: 1.8.1
24
+ version:
25
+ platform: ruby
26
+ signing_key:
27
+ cert_chain:
28
+ authors: []
29
+
30
+ files:
31
+ - lib/CVS
32
+ - lib/ldapmapper.rb
33
+ test_files:
34
+ - test/testldapmapper.rb
35
+ rdoc_options: []
36
+
37
+ extra_rdoc_files: []
38
+
39
+ executables: []
40
+
41
+ extensions: []
42
+
43
+ requirements: []
44
+
45
+ dependencies: []
46
+