ldapmapper 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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
+