ruby-activeldap 0.8.1 → 0.8.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (65) hide show
  1. data/CHANGES +5 -0
  2. data/Manifest.txt +91 -25
  3. data/README +22 -0
  4. data/Rakefile +41 -8
  5. data/TODO +1 -6
  6. data/examples/config.yaml.example +5 -0
  7. data/examples/example.der +0 -0
  8. data/examples/example.jpg +0 -0
  9. data/examples/groupadd +41 -0
  10. data/examples/groupdel +35 -0
  11. data/examples/groupls +49 -0
  12. data/examples/groupmod +42 -0
  13. data/examples/lpasswd +55 -0
  14. data/examples/objects/group.rb +13 -0
  15. data/examples/objects/ou.rb +4 -0
  16. data/examples/objects/user.rb +20 -0
  17. data/examples/ouadd +38 -0
  18. data/examples/useradd +45 -0
  19. data/examples/useradd-binary +50 -0
  20. data/examples/userdel +34 -0
  21. data/examples/userls +50 -0
  22. data/examples/usermod +42 -0
  23. data/examples/usermod-binary-add +47 -0
  24. data/examples/usermod-binary-add-time +51 -0
  25. data/examples/usermod-binary-del +48 -0
  26. data/examples/usermod-lang-add +43 -0
  27. data/lib/active_ldap.rb +213 -214
  28. data/lib/active_ldap/adapter/base.rb +461 -0
  29. data/lib/active_ldap/adapter/ldap.rb +232 -0
  30. data/lib/active_ldap/adapter/ldap_ext.rb +69 -0
  31. data/lib/active_ldap/adapter/net_ldap.rb +288 -0
  32. data/lib/active_ldap/adapter/net_ldap_ext.rb +29 -0
  33. data/lib/active_ldap/association/belongs_to.rb +3 -1
  34. data/lib/active_ldap/association/belongs_to_many.rb +5 -6
  35. data/lib/active_ldap/association/has_many.rb +9 -17
  36. data/lib/active_ldap/association/has_many_wrap.rb +4 -5
  37. data/lib/active_ldap/attributes.rb +4 -0
  38. data/lib/active_ldap/base.rb +201 -56
  39. data/lib/active_ldap/configuration.rb +11 -1
  40. data/lib/active_ldap/connection.rb +15 -9
  41. data/lib/active_ldap/distinguished_name.rb +246 -0
  42. data/lib/active_ldap/ldap_error.rb +74 -0
  43. data/lib/active_ldap/object_class.rb +9 -5
  44. data/lib/active_ldap/schema.rb +50 -9
  45. data/lib/active_ldap/validations.rb +11 -13
  46. data/rails/plugin/active_ldap/generators/scaffold_al/scaffold_al_generator.rb +7 -0
  47. data/rails/plugin/active_ldap/generators/scaffold_al/templates/ldap.yml +21 -0
  48. data/rails/plugin/active_ldap/init.rb +10 -4
  49. data/test/al-test-utils.rb +46 -3
  50. data/test/run-test.rb +16 -4
  51. data/test/test-unit-ext/always-show-result.rb +28 -0
  52. data/test/test-unit-ext/priority.rb +163 -0
  53. data/test/test_adapter.rb +81 -0
  54. data/test/test_attributes.rb +8 -1
  55. data/test/test_base.rb +132 -3
  56. data/test/test_base_per_instance.rb +14 -3
  57. data/test/test_connection.rb +19 -0
  58. data/test/test_dn.rb +161 -0
  59. data/test/test_find.rb +24 -0
  60. data/test/test_object_class.rb +15 -2
  61. data/test/test_schema.rb +108 -1
  62. metadata +111 -41
  63. data/lib/active_ldap/adaptor/base.rb +0 -29
  64. data/lib/active_ldap/adaptor/ldap.rb +0 -466
  65. data/lib/active_ldap/ldap.rb +0 -113
@@ -0,0 +1,48 @@
1
+ #!/usr/bin/ruby -W0
2
+
3
+ base = File.expand_path(File.join(File.dirname(__FILE__), ".."))
4
+ $LOAD_PATH << File.join(base, "lib")
5
+ $LOAD_PATH << File.join(base, "examples")
6
+
7
+ require 'active_ldap'
8
+ require 'objects/user'
9
+ require 'objects/group'
10
+
11
+ argv, opts, options = ActiveLdap::Command.parse_options do |opts, options|
12
+ opts.banner += " USER_NAME CN UID"
13
+ end
14
+
15
+ if argv.size == 3
16
+ name, cn, uid = argv
17
+ else
18
+ $stderr.puts opts
19
+ exit 1
20
+ end
21
+
22
+ pwb = Proc.new do |user|
23
+ ActiveLdap::Command.read_password("[#{user}] Password: ")
24
+ end
25
+
26
+ ActiveLdap::Base.establish_connection(:password_block => pwb,
27
+ :allow_anonymous => false)
28
+
29
+ unless User.exists?(name)
30
+ $stderr.puts("User #{name} doesn't exist.")
31
+ exit 1
32
+ end
33
+
34
+ user = User.find(name)
35
+ user.cn = cn
36
+ user.uid_number = uid
37
+ user.gid_number = uid
38
+
39
+ if user.classes.include?('strongAuthenticationUser')
40
+ user.user_certificate = nil
41
+ user.remove_class('strongAuthenticationUser')
42
+ end
43
+
44
+ unless user.save
45
+ puts "failed"
46
+ puts user.errors.full_messages
47
+ exit 1
48
+ end
@@ -0,0 +1,43 @@
1
+ #!/usr/bin/ruby -W0
2
+
3
+ base = File.expand_path(File.join(File.dirname(__FILE__), ".."))
4
+ $LOAD_PATH << File.join(base, "lib")
5
+ $LOAD_PATH << File.join(base, "examples")
6
+
7
+ require 'active_ldap'
8
+ require 'objects/user'
9
+ require 'objects/group'
10
+
11
+ argv, opts, options = ActiveLdap::Command.parse_options do |opts, options|
12
+ opts.banner += " USER_NAME CN UID"
13
+ end
14
+
15
+ if argv.size == 3
16
+ name, cn, uid = argv
17
+ else
18
+ $stderr.puts opts
19
+ exit 1
20
+ end
21
+
22
+ pwb = Proc.new do |user|
23
+ ActiveLdap::Command.read_password("[#{user}] Password: ")
24
+ end
25
+
26
+ ActiveLdap::Base.establish_connection(:password_block => pwb,
27
+ :allow_anonymous => false)
28
+
29
+ unless User.exists?(name)
30
+ $stderr.puts("User #{name} doesn't exist.")
31
+ exit 1
32
+ end
33
+
34
+ user = User.find(name)
35
+ user.cn = [cn, {'lang-en-us' => cn}]
36
+ user.uid_number = uid
37
+ user.gid_number = uid
38
+
39
+ unless user.save
40
+ puts "failed"
41
+ puts user.errors.full_messages
42
+ exit 1
43
+ end
data/lib/active_ldap.rb CHANGED
@@ -1,21 +1,21 @@
1
1
  #!/usr/bin/ruby
2
- # = Ruby/ActiveLdap
2
+ # = Ruby/ActiveLdap
3
3
  #
4
4
  # "Ruby/ActiveLdap" Copyright (C) 2004,2005 Will Drewry mailto:will@alum.bu.edu
5
5
  #
6
6
  # == Introduction
7
- #
7
+ #
8
8
  # Ruby/ActiveLdap is a novel way of interacting with LDAP. Most interaction with
9
9
  # LDAP is done using clunky LDIFs, web interfaces, or with painful APIs that
10
10
  # required a thick reference manual nearby. Ruby/ActiveLdap aims to fix that.
11
11
  # Inspired by ActiveRecord[http://activerecord.rubyonrails.org], Ruby/ActiveLdap provides an
12
12
  # object oriented interface to LDAP entries.
13
- #
13
+ #
14
14
  # The target audience is system administrators and LDAP users everywhere that
15
15
  # need quick, clean access to LDAP in Ruby.
16
- #
16
+ #
17
17
  # === What's LDAP?
18
- #
18
+ #
19
19
  # LDAP stands for "Lightweight Directory Access Protocol." Basically this means
20
20
  # that it is the protocol used for accessing LDAP servers. LDAP servers
21
21
  # lightweight directories. An LDAP server can contain anything from a simple
@@ -24,32 +24,32 @@
24
24
  # assume some familiarity with using LDAP as a centralized authentication and
25
25
  # authorization server for Unix systems. (Unfortunately, I've yet to try this
26
26
  # against Microsoft's ActiveDirectory, despite what the name implies.)
27
- #
28
- # Further reading:
27
+ #
28
+ # Further reading:
29
29
  # * RFC1777[http://www.faqs.org/rfcs/rfc1777.html] - Lightweight Directory Access Protocol
30
30
  # * OpenLDAP[http://www.openldap.org]
31
- #
31
+ #
32
32
  # === So why use Ruby/ActiveLdap?
33
- #
33
+ #
34
34
  # Well if you like to fumble around in the dark, dank innards of LDAP, you can
35
35
  # quit reading now. However, if you'd like a cleaner way to integrate LDAP in to
36
36
  # your existing code, hopefully that's why you'll want to use Ruby/ActiveLdap.
37
- #
37
+ #
38
38
  # Using LDAP directly (even with the excellent Ruby/LDAP), leaves you bound to
39
39
  # the world of the predefined LDAP API. While this API is important for many
40
40
  # reasons, having to extract code out of LDAP search blocks and create huge
41
41
  # arrays of LDAP.mod entries make code harder to read, less intuitive, and just
42
42
  # less fun to write. Hopefully, Ruby/ActiveLdap will remedy all of these
43
43
  # problems!
44
- #
44
+ #
45
45
  # == Getting Started
46
- #
46
+ #
47
47
  # Ruby/ActiveLdap does have some overhead when you get started. You must not
48
48
  # only install the package and all of it's requirements, but you must also make
49
49
  # customizations that will let it work in your environment.
50
- #
50
+ #
51
51
  # === Requirements
52
- #
52
+ #
53
53
  # * Ruby[http://www.ruby-lang.org] 1.8.x
54
54
  # * Ruby/LDAP[http://ruby-ldap.sourceforge.net]
55
55
  # * Log4r[http://log4r.sourceforge.net]
@@ -57,134 +57,134 @@
57
57
  # * An LDAP server compatible with Ruby/LDAP: OpenLDAP[http://www.openldap.org], etc
58
58
  # - Your LDAP server must allow root_dse queries to allow for schema queries
59
59
  # * Examples also require: Ruby/Password[http://raa.ruby-lang.org/project/ruby-password/]
60
- #
60
+ #
61
61
  # === Installation
62
- #
62
+ #
63
63
  # Assuming all the requirements are installed, you can install by grabbing the latest tgz file from
64
64
  # the download site[http://projects.dataspill.org/libraries/ruby/activeldap/download.html].
65
- #
65
+ #
66
66
  # The following steps will get the Ruby/ActiveLdap installed in no time!
67
- #
67
+ #
68
68
  # $ tar -xzvf ruby-activeldap-current.tgz
69
69
  # $ cd ruby-activeldap-VERSION
70
- #
70
+ #
71
71
  # Edit lib/active_ldap/configuration.rb replacing values to match what will work
72
72
  # with your LDAP servers. Please note that those variables are required, but can
73
73
  # be overridden in any program as detailed later in this document. Also make
74
74
  # sure that "ROOT" stays all upcase.
75
- #
75
+ #
76
76
  # Now run:
77
- #
77
+ #
78
78
  # $ ruby setup.rb config
79
79
  # $ ruby setup.rb setup
80
80
  # $ (as root) ruby setup.rb install
81
- #
81
+ #
82
82
  # Now as a quick test, you can run:
83
- #
83
+ #
84
84
  # $ irb
85
85
  # irb> require 'active_ldap'
86
86
  # => true
87
87
  # irb> exit
88
- #
88
+ #
89
89
  # If the require returns false or an exception is raised, there has been a
90
90
  # problem with the installation. You may need to customize what setup.rb does on
91
91
  # install.
92
- #
93
- #
92
+ #
93
+ #
94
94
  # === Customizations
95
- #
95
+ #
96
96
  # Now that Ruby/ActiveLdap is installed and working, we still have a few more
97
97
  # steps to make it useful for programming.
98
- #
98
+ #
99
99
  # Let's say that you are writing a Ruby program for managing user and group
100
100
  # accounts in LDAP. I will use this as the running example throughout the
101
101
  # document.
102
- #
102
+ #
103
103
  # You will want to make a directory called 'ldapadmin' wherever is convenient. Under this directory,
104
104
  # you'll want to make sure you have a 'lib' directory.
105
- #
105
+ #
106
106
  # $ cd ~
107
107
  # $ mkdir ldapadmin
108
108
  # $ cd ldapadmin
109
109
  # $ mkdir lib
110
110
  # $ cd lib
111
- #
111
+ #
112
112
  # The lib directory is where we'll be making customizations. You can, of course,
113
113
  # make this changes somewhere in Ruby's default search path to make this
114
114
  # accessible to every Ruby scripts. Enough of my babbling, I'm sure you'd like to
115
115
  # know what we're going to put in lib/.
116
- #
116
+ #
117
117
  # We're going to put extension classes in there. What are extension classes you say . . .
118
- #
119
- #
118
+ #
119
+ #
120
120
  # == Usage
121
- #
121
+ #
122
122
  # This section covers using Ruby/ActiveLdap from writing extension classes to
123
123
  # writing applications that use them.
124
- #
124
+ #
125
125
  # Just to give a taste of what's to come, here is a quick example using irb:
126
- #
126
+ #
127
127
  # irb> require 'active_ldap'
128
- #
128
+ #
129
129
  # Here's an extension class that maps to the LDAP Group objects:
130
- #
130
+ #
131
131
  # irb> class Group < ActiveLdap::Base
132
132
  # irb* ldap_mapping
133
133
  # irb* end
134
- #
134
+ #
135
135
  # Here is the Group class in use:
136
- #
136
+ #
137
137
  # irb> all_groups = Group.find(:all, '*').collect {|group| group.cn}
138
138
  # => ["root", "daemon", "bin", "sys", "adm", "tty", ..., "develop"]
139
- #
139
+ #
140
140
  # irb> group = Group.find("develop")
141
141
  # => #<Group:0x..........>
142
- #
142
+ #
143
143
  # irb> group.members.collect {|member| member.uid}
144
144
  # => ["drewry"]
145
- #
145
+ #
146
146
  # irb> group.cn
147
147
  # => "develop"
148
- #
148
+ #
149
149
  # irb> group.gid_number
150
150
  # => "1003"
151
- #
151
+ #
152
152
  # That's it! No let's get back in to it.
153
153
  #
154
154
  # === Extension Classes
155
- #
155
+ #
156
156
  # Extension classes are classes that are subclassed from ActiveLdap::Base. They
157
157
  # are used to represent objects in your LDAP server abstractly.
158
- #
158
+ #
159
159
  # ==== Why do I need them?
160
- #
160
+ #
161
161
  # Extension classes are what make Ruby/ActiveLdap "active"! They do all the
162
162
  # background work to make easy-to-use objects by mapping the LDAP object's
163
163
  # attributes on to a Ruby class.
164
- #
165
- #
164
+ #
165
+ #
166
166
  # ==== Special Methods
167
- #
167
+ #
168
168
  # I will briefly talk about each of the methods you can use when defining an
169
169
  # extension class. In the above example, I only made one special method call
170
170
  # inside the Group class. More than likely, you will want to more than that.
171
- #
171
+ #
172
172
  # ===== ldap_mapping
173
- #
173
+ #
174
174
  # ldap_mapping is the only required method to setup an extension class for use
175
175
  # with Ruby/ActiveLdap. It must be called inside of a subclass as shown above.
176
- #
176
+ #
177
177
  # Below is a much more realistic Group class:
178
- #
178
+ #
179
179
  # class Group < ActiveLdap::Base
180
180
  # ldap_mapping :dn_attribute => 'cn',
181
181
  # :prefix => 'ou=Groups', :classes => ['top', 'posixGroup']
182
182
  # :scope => LDAP::LDAP_SCOPE_ONELEVEL
183
183
  # end
184
- #
185
- # As you can see, this method is used for defining how this class maps in to LDAP. Let's say that
184
+ #
185
+ # As you can see, this method is used for defining how this class maps in to LDAP. Let's say that
186
186
  # my LDAP tree looks something like this:
187
- #
187
+ #
188
188
  # * dc=dataspill,dc=org
189
189
  # |- ou=People,dc=dataspill,dc=org
190
190
  # |+ ou=Groups,dc=dataspill,dc=org
@@ -192,24 +192,24 @@
192
192
  # |- cn=develop,ou=Groups,dc=dataspill,dc=org
193
193
  # |- cn=root,ou=Groups,dc=dataspill,dc=org
194
194
  # |- ...
195
- #
195
+ #
196
196
  # Under ou=People I store user objects, and under ou=Groups, I store group
197
197
  # objects. What |ldap_mapping| has done is mapped the class in to the LDAP tree
198
198
  # abstractly. With the given :dnattr and :prefix, it will only work for entries
199
199
  # under ou=Groups,dc=dataspill,dc=org using the primary attribute 'cn' as the
200
200
  # beginning of the distinguished name.
201
- #
201
+ #
202
202
  # Just for clarity, here's how the arguments map out:
203
- #
203
+ #
204
204
  # cn=develop,ou=Groups,dc=dataspill,dc=org
205
205
  # ^^ ^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^
206
206
  # :dn_attribute | |
207
207
  # :prefix |
208
208
  # :base from configuration.rb
209
- #
209
+ #
210
210
  # :scope tells ActiveLdap to only search under ou=Groups, and not to look deeper
211
211
  # for dnattr matches. (e.g. cn=develop,ou=DevGroups,ou=Groups,dc=dataspill,dc=org)
212
- #
212
+ #
213
213
  # Something's missing: :classes. :classes is used to tell Ruby/ActiveLdap what
214
214
  # the minimum requirement is when creating a new object. LDAP uses objectClasses
215
215
  # to define what attributes a LDAP object may have. Ruby/ActiveLdap needs to know
@@ -222,48 +222,48 @@
222
222
  # implementation choices with most LDAP servers, once an object is created, its
223
223
  # structural objectclasses may not be removed (or replaced). Setting a sane default
224
224
  # may help avoid programmer error later.
225
- #
225
+ #
226
226
  # :classes isn't the only optional argument. If :dn_attribute is left off,
227
227
  # it defaults to underscored class name or 'cn'. If :prefix is left off,
228
228
  # it will default to 'ou=PLURALIZED_CLASSNAME'. In this
229
229
  # case, it would be 'ou=Groups'.
230
- #
230
+ #
231
231
  # :classes should be an Array. :dn_attribute should be a String and so should
232
232
  # :prefix.
233
- #
234
- #
233
+ #
234
+ #
235
235
  # ===== belongs_to
236
- #
236
+ #
237
237
  # This method allows an extension class to make use of other extension classes
238
238
  # tying objects together across the LDAP tree. Often, user objects will be
239
239
  # members of, or belong_to, Group objects.
240
- #
240
+ #
241
241
  # * dc=dataspill,dc=org
242
242
  # |+ ou=People,dc=dataspill,dc=org
243
243
  # \
244
244
  # |- uid=drewry,ou=People,dc=dataspill,dc=org
245
245
  # |- ou=Groups,dc=dataspill,dc=org
246
- #
247
- #
246
+ #
247
+ #
248
248
  # In the above tree, one such example would be user 'drewry' who is a part of the
249
249
  # group 'develop'. You can see this by looking at the 'memberUid' field of 'develop'.
250
- #
250
+ #
251
251
  # irb> develop = Group.find('develop')
252
252
  # => ...
253
253
  # irb> develop.memberUid
254
254
  # => ['drewry', 'builder']
255
- #
255
+ #
256
256
  # If we look at the LDAP entry for 'drewry', we do not see any references to
257
257
  # group 'develop'. In order to remedy that, we can use belongs_to
258
- #
258
+ #
259
259
  # irb> class User < ActiveLdap::Base
260
260
  # irb* ldap_mapping :dn_attribute => 'uid', :prefix => 'People', :classes => ['top','account']
261
261
  # irb* belongs_to :groups, :class => 'Group', :many => 'memberUid', :foreign_key => 'uid'
262
262
  # irb* end
263
- #
263
+ #
264
264
  # Now, class User will have a method called 'groups' which will retrieve all
265
265
  # Group objects that a user is in.
266
- #
266
+ #
267
267
  # irb> me = User.find('drewry')
268
268
  # irb> me.groups
269
269
  # => [#<Group:0x000001 ...>, #<Group:0x000002 ...>, ...]
@@ -273,16 +273,16 @@
273
273
  # "develop"
274
274
  # => nil
275
275
  # (Note: nil is just there to make the output cleaner...)
276
- #
276
+ #
277
277
  # TIP: If you weren't sure what the distinguished name attribute was for Group,
278
278
  # you could also do the following:
279
- #
279
+ #
280
280
  # irb> me.groups.each { |group| p group.id };nil
281
281
  # "cdrom"
282
282
  # "audio"
283
283
  # "develop"
284
284
  # => nil
285
- #
285
+ #
286
286
  # Now let's talk about the arguments. The first argument is the name of the
287
287
  # method you wish to create. In this case, we created a method called groups
288
288
  # using the symbol :groups. The next collection of arguments are actually a Hash
@@ -294,78 +294,78 @@
294
294
  # should be looked up in Group under the primary key. If :foreign_key is left
295
295
  # off of the argument list, it is assumed to be the dn_attribute. With this in
296
296
  # mind, the above definition could become:
297
- #
297
+ #
298
298
  # irb> class User < ActiveLdap::Base
299
299
  # irb* ldap_mapping :dnattr => 'uid', :prefix => 'People', :classes => ['top','account']
300
300
  # irb* belongs_to :groups, :class => 'Group', :many => 'memberUid'
301
301
  # irb* end
302
- #
302
+ #
303
303
  # In addition, you can do simple membership tests by doing the following:
304
- #
304
+ #
305
305
  # irb> me.groups.member? 'root'
306
306
  # => false
307
307
  # irb> me.groups.member? 'develop'
308
308
  # => true
309
- #
309
+ #
310
310
  # ===== has_many
311
- #
311
+ #
312
312
  # This method is the opposite of belongs_to. Instead of checking other objects in
313
313
  # other parts of the LDAP tree to see if you belong to them, you have multiple
314
314
  # objects from other trees listed in your object. To show this, we can just
315
315
  # invert the example from above:
316
- #
316
+ #
317
317
  # class Group < ActiveLdap::Base
318
318
  # ldap_mapping :dn_attribute => 'cn', :prefix => 'ou=Groups', :classes => ['top', 'posixGroup']
319
319
  # has_many :members, :class => "User", :wrap => "memberUid", :primary_key => 'uid'
320
320
  # end
321
- #
321
+ #
322
322
  # Now we can see that group develop has user 'drewry' as a member, and it can
323
323
  # even return all responses in object form just like belongs_to methods.
324
- #
324
+ #
325
325
  # irb> develop = Group.find('develop')
326
326
  # => ...
327
327
  # irb> develop.members
328
328
  # => [#<User:0x000001 ...>, #<User:...>]
329
- #
330
- #
329
+ #
330
+ #
331
331
  # The arguments for has_many follow the exact same idea that belongs_to's
332
332
  # arguments followed. :wrap's contents are used to search for matching
333
333
  # :primary_key content. If :primary_key is not specified, it defaults to the
334
334
  # dn_attribute of the specified :class.
335
- #
335
+ #
336
336
  # === Using these new classes
337
- #
337
+ #
338
338
  # These new classes have many method calls. Many of them are automatically
339
339
  # generated to provide access to the LDAP object's attributes. Other were defined
340
340
  # during class creation by special methods like belongs_to. There are a few other
341
341
  # methods that do not fall in to these categories.
342
- #
343
- #
342
+ #
343
+ #
344
344
  # ==== .find
345
- #
345
+ #
346
346
  # .find is a class method that is accessible from any subclass of Base that has
347
347
  # 'ldap_mapping' called. When called it returns the first match of the given
348
348
  # class.
349
- #
349
+ #
350
350
  # irb> Group.find('*').cn
351
351
  # => "root"
352
- #
352
+ #
353
353
  # In this simple example, Group.find took the search string of 'deve*' and
354
354
  # searched for the first match in Group where the dnattr matched the query. This
355
355
  # is the simplest example of .find.
356
- #
356
+ #
357
357
  # irb> Group.find(:all, '*').collect {|group| group.cn}
358
358
  # => ["root", "daemon", "bin", "sys", "adm", "tty", ..., "develop"]
359
- #
359
+ #
360
360
  # Here .find(:all) returns all matches to the same query. Both .find and
361
361
  # .find(:all) also can take more expressive arguments:
362
- #
362
+ #
363
363
  # irb> Group.find(:all, :attribute => 'gidNumber', :value => '1003').collect {|group| group.cn}
364
364
  # => ["develop"]
365
- #
365
+ #
366
366
  # So it is pretty clear what :attribute and :value do - they are used to query as
367
367
  # :attribute=:value.
368
- #
368
+ #
369
369
  # If :attribute is unspecified, it defaults to the dn_attribute.
370
370
  #
371
371
  # It is also possible to override :attribute and :value by specifying :filter. This
@@ -387,87 +387,83 @@
387
387
  # * :attributes defaults to [] and is the list of attributes you want back. Empty means all of them.
388
388
  #
389
389
  # ==== #valid?
390
- #
390
+ #
391
391
  # valid? is a method that verifies that all attributes that are required by the
392
392
  # objects current objectClasses are populated.
393
- #
393
+ #
394
394
  # ==== #save
395
- #
395
+ #
396
396
  # save is a method that writes any changes to an object back to the LDAP server.
397
397
  # It automatically handles the addition of new objects, and the modification of
398
398
  # existing ones.
399
- #
399
+ #
400
400
  # ==== .exists?
401
- #
401
+ #
402
402
  # exists? is a simple method which returns true is the current object exists in
403
403
  # LDAP, or false if it does not.
404
- #
404
+ #
405
405
  # irb> User.exists?("dshadsadsa")
406
406
  # => false
407
- #
408
- #
407
+ #
408
+ #
409
409
  # === ActiveLdap::Base
410
- #
410
+ #
411
411
  # ActiveLdap::Base has come up a number of times in the examples above. Every
412
412
  # time, it was being used as the super class for the wrapper objects. While this
413
413
  # is it's main purpose, it also handles quite a bit more in the background.
414
- #
414
+ #
415
415
  # ==== What is it?
416
- #
416
+ #
417
417
  # ActiveLdap::Base is the heart of Ruby/ActiveLdap. It does all the schema
418
418
  # parsing for validation and attribute-to-method mangling as well as manage the
419
419
  # connection to LDAP.
420
- #
420
+ #
421
421
  # ===== establish_connection
422
- #
422
+ #
423
423
  # Base.establish_connection takes many (optional) arguments and is used to
424
424
  # connect to the LDAP server. Sometimes you will want to connect anonymously
425
- # and other times over TLS with user credentials. Base.connect is here to do
426
- # all of that for you.
427
- #
428
- #
425
+ # and other times over TLS with user credentials. Base.establish_connection is
426
+ # here to do all of that for you.
427
+ #
428
+ #
429
429
  # By default, if you call any subclass of Base, such as Group, it will call
430
430
  # Base.establish_connection() if these is no active LDAP connection. If your
431
431
  # server allows anonymous binding, and you only want to access data in a
432
432
  # read-only fashion, you won't need to call Base.establish_connection. Here
433
433
  # is a fully parameterized call:
434
- #
435
- # Base.connect(
434
+ #
435
+ # Base.establish_connection(
436
436
  # :host => 'ldap.dataspill.org',
437
437
  # :port => 389,
438
438
  # :base => 'dc=dataspill,dc=org',
439
- # :bind_format => "uid=%s,ou=People,dc=dataspill,dc=org",
440
439
  # :logger => log4r_obj,
441
- # :user => 'drewry',
440
+ # :bind_dn => "uid=drewry,ou=People,dc=dataspill,dc=org",
442
441
  # :password_block => Proc.new { 'password12345' },
443
442
  # :allow_anonymous => false,
444
443
  # :try_sasl => false
445
444
  # )
446
- #
445
+ #
447
446
  # There are quite a few arguments, but luckily many of them have safe defaults:
448
447
  # * :host defaults to @@host from configuration.rb waaay back at the setup.rb stage.@
449
448
  # * :port defaults to @@port from configuration.rb as well
450
449
  # * :base defaults to Base.base() from configuration.rb
451
- # * :bind_format defaults @@bind_format from configuration.rb
450
+ # * :bind_dn defaults @@bind_format from configuration.rb
452
451
  # * :logger defaults to a Log4r object that prints fatal messages to stderr
453
- # * :user defaults to ENV['user']
454
452
  # * :password_block defaults to nil
455
453
  # * :allow_anonymous defaults to true
456
454
  # * :try_sasl defaults to false - see Advanced Topics for more on this one.
457
- #
458
- #
455
+ #
456
+ #
459
457
  # Most of these are obvious, but I'll step through them for completeness:
460
458
  # * :host defines the LDAP server hostname to connect to.
461
459
  # * :port defines the LDAP server port to connect to.
462
460
  # * :method defines the type of connection - :tls, :ssl, :plain
463
461
  # * :base specifies the LDAP search base to use with the prefixes defined in all
464
462
  # subclasses.
465
- # * :bind_format specifies what your server expects when attempting to bind with
463
+ # * :bind_dn specifies what your server expects when attempting to bind with
466
464
  # credentials.
467
465
  # * :logger accepts a custom log4r object to integrate with any other logging
468
466
  # your application uses.
469
- # * :user gives the username to substitute into bind_format for binding with
470
- # credentials
471
467
  # * :password_block, if defined, give the Proc block for acquiring the password
472
468
  # * :password, if defined, give the user's password as a String
473
469
  # * :store_password indicates whether the password should be stored, or if used
@@ -483,13 +479,13 @@
483
479
  # * :timeout - time in seconds - defaults to disabled. This CAN interrupt search() requests. Be warned.
484
480
  # * :retry_on_timeout - whether to reconnect when timeouts occur. Defaults to true
485
481
  # See lib/configuration.rb for defaults for each option
486
- #
482
+ #
487
483
  # Base.establish_connection both connects and binds in one step. It follows
488
484
  # roughly the following approach:
489
- #
485
+ #
490
486
  # * Connect to host:port using :method
491
- #
492
- # * If user and password_block/password, attempt to bind with credentials.
487
+ #
488
+ # * If bind_dn and password_block/password, attempt to bind with credentials.
493
489
  # * If that fails or no password_block and anonymous allowed, attempt to bind
494
490
  # anonymously.
495
491
  # * If that fails, error out.
@@ -497,62 +493,62 @@
497
493
  # On connect, the configuration options passed in are stored in an internal class variable
498
494
  # @configuration which is used to cache the information without ditching the defaults passed in
499
495
  # from configuration.rb
500
- #
496
+ #
501
497
  # ===== connection
502
- #
498
+ #
503
499
  # Base.connection returns the ActiveLdap::Connection object.
504
- #
500
+ #
505
501
  # === Exceptions
506
- #
502
+ #
507
503
  # There are a few custom exceptions used in Ruby/ActiveLdap. They are detailed below.
508
- #
504
+ #
509
505
  # ==== DeleteError
510
- #
506
+ #
511
507
  # This exception is raised when #delete fails. It will include LDAP error
512
508
  # information that was passed up during the error.
513
- #
509
+ #
514
510
  # ==== SaveError
515
- #
511
+ #
516
512
  # This exception is raised when there is a problem in #save updating or creating
517
513
  # an LDAP entry. Often the error messages are cryptic. Looking at the server
518
514
  # logs or doing an Ethereal[http://www.ethereal.com] dump of the connection will
519
515
  # often provide better insight.
520
- #
516
+ #
521
517
  # ==== AuthenticationError
522
- #
518
+ #
523
519
  # This exception is raised during Base.establish_connection if no valid authentication methods
524
520
  # succeeded.
525
- #
521
+ #
526
522
  # ==== ConnectionError
527
- #
528
- # This exception is raised during Base.connect if no valid connection to the
529
- # LDAP server could be created. Check you configuration.rb, Base.connect
530
- # arguments, and network connectivity! Also check your LDAP server logs to see
531
- # if it ever saw the request.
523
+ #
524
+ # This exception is raised during Base.establish_connection if no valid
525
+ # connection to the LDAP server could be created. Check you configuration.rb,
526
+ # Base.establish_connection arguments, and network connectivity! Also check
527
+ # your LDAP server logs to see if it ever saw the request.
532
528
  #
533
529
  # ==== ObjectClassError
534
530
  #
535
531
  # This exception is raised when an object class is used that is not defined
536
532
  # in the schema.
537
- #
533
+ #
538
534
  # === Others
539
- #
535
+ #
540
536
  # Other exceptions may be raised by the Ruby/LDAP module, or by other subsystems.
541
537
  # If you get one of these exceptions and think it should be wrapped, write me an
542
538
  # email and let me know where it is and what you expected. For faster results,
543
539
  # email a patch!
544
- #
540
+ #
545
541
  # === Putting it all together
546
- #
542
+ #
547
543
  # Now that all of the components of Ruby/ActiveLdap have been covered, it's time
548
544
  # to put it all together! The rest of this section will show the steps to setup
549
545
  # example user and group management scripts for use with the LDAP tree described
550
546
  # above.
551
- #
547
+ #
552
548
  # All of the scripts here are in the package's examples/ directory.
553
- #
549
+ #
554
550
  # ==== Setting up lib/
555
- #
551
+ #
556
552
  # In ldapadmin/lib/ create the file user.rb:
557
553
  # cat <<EOF
558
554
  # class User < ActiveLdap::Base
@@ -560,7 +556,7 @@
560
556
  # belongs_to :groups, :class => 'Group', :wrap => 'memberUid'
561
557
  # end
562
558
  # EOF
563
- #
559
+ #
564
560
  # In ldapadmin/lib/ create the file group.rb:
565
561
  # cat <<EOF
566
562
  # class Group < ActiveLdap::Base
@@ -569,20 +565,20 @@
569
565
  # has_many :primary_members, :class => 'User', :foreign_key => 'gidNumber', :primary_key => 'gidNumber'
570
566
  # end # Group
571
567
  # EOF
572
- #
568
+ #
573
569
  # Now, we can write some small scripts to do simple management tasks.
574
- #
570
+ #
575
571
  # ==== Creating LDAP entries
576
- #
572
+ #
577
573
  # Now let's create a really dumb script for adding users - ldapadmin/useradd:
578
- #
574
+ #
579
575
  # #!/usr/bin/ruby -W0
580
- #
576
+ #
581
577
  # require 'active_ldap'
582
578
  # require 'lib/user'
583
579
  # require 'lib/group'
584
580
  # require 'password'
585
- #
581
+ #
586
582
  # argv, opts, options = ActiveLdap::Command.parse_options do |opts, options|
587
583
  # opts.banner += " USER_NAME CN UID"
588
584
  # end
@@ -620,15 +616,15 @@
620
616
  # end
621
617
  #
622
618
  # ==== Managing LDAP entries
623
- #
619
+ #
624
620
  # Now let's create another dumb script for modifying users - ldapadmin/usermod:
625
- #
621
+ #
626
622
  # #!/usr/bin/ruby -W0
627
- #
623
+ #
628
624
  # require 'active_ldap'
629
625
  # require 'lib/user'
630
626
  # require 'lib/group'
631
- #
627
+ #
632
628
  # argv, opts, options = ActiveLdap::Command.parse_options do |opts, options|
633
629
  # opts.banner += " USER_NAME CN UID"
634
630
  # end
@@ -663,16 +659,16 @@
663
659
  # end
664
660
  #
665
661
  # ==== Removing LDAP entries
666
- #
662
+ #
667
663
  # And finally, a dumb script for removing user - ldapadmin/userdel:
668
- #
669
- #
664
+ #
665
+ #
670
666
  # #!/usr/bin/ruby -W0
671
- #
667
+ #
672
668
  # require 'active_ldap'
673
669
  # require 'lib/user'
674
670
  # require 'lib/group'
675
- #
671
+ #
676
672
  # argv, opts, options = ActiveLdap::Command.parse_options do |opts, options|
677
673
  # opts.banner += " USER_NAME"
678
674
  # end
@@ -699,9 +695,9 @@
699
695
  # User.destroy(name)
700
696
  #
701
697
  # === Advanced Topics
702
- #
698
+ #
703
699
  # Below are some situation tips and tricks to get the most out of Ruby/ActiveLdap.
704
- #
700
+ #
705
701
  #
706
702
  # ==== Binary data and other subtypes
707
703
  #
@@ -721,14 +717,14 @@
721
717
  # => ...
722
718
  # irb> user.save
723
719
  #
724
- # So that's a lot to take in. Here's what is going on. I just set the LDAP
720
+ # So that's a lot to take in. Here's what is going on. I just set the LDAP
725
721
  # object's cn to "wad" and cn:lang-en-us to ["wad", "Will Drewry"].
726
722
  # Anytime a LDAP subtype is required, you must encapsulate the data in a Hash.
727
723
  #
728
724
  # But wait a minute, I just read in a binary certificate without wrapping it up.
729
- # So any binary attribute _that requires ;binary subtyping_ will automagically
730
- # get wrapped in {'binary' => value} if you don't do it. This keeps your #writes
731
- # from breaking, and my code from crying. For correctness, I could have easily
725
+ # So any binary attribute _that requires ;binary subtyping_ will automagically
726
+ # get wrapped in {'binary' => value} if you don't do it. This keeps your #writes
727
+ # from breaking, and my code from crying. For correctness, I could have easily
732
728
  # done the following:
733
729
  #
734
730
  # irb> user.user_certificate = {'binary' => File.read('example.der')}
@@ -737,37 +733,37 @@
737
733
  # One example is jpegPhoto. You can use it as jpegPhoto;binary or just as jpegPhoto.
738
734
  # Since the schema dictates that it is a binary value, Ruby/ActiveLdap will write
739
735
  # it as binary, but the subtype will not be automatically appended as above. The
740
- # use of the subtype on attributes like jpegPhoto is ultimately decided by the
736
+ # use of the subtype on attributes like jpegPhoto is ultimately decided by the
741
737
  # LDAP site policy and not by any programmatic means.
742
738
  #
743
739
  # The only subtypes defined in LDAPv3 are lang-* and binary. These can be nested
744
740
  # though:
745
741
  #
746
742
  # irb> user.cn = [{'lang-JP-jp' => {'binary' => 'somejp'}}]
747
- #
743
+ #
748
744
  # As I understand it, OpenLDAP does not support nested subtypes, but some
749
745
  # documentation I've read suggests that Netscape's LDAP server does. I only
750
- # have access to OpenLDAP. If anyone tests this out, please let me know how it
746
+ # have access to OpenLDAP. If anyone tests this out, please let me know how it
751
747
  # goes!
752
748
  #
753
749
  #
754
750
  # And that pretty much wraps up this section.
755
751
  #
756
752
  # ==== Further integration with your environment aka namespacing
757
- #
753
+ #
758
754
  # If you want this to cleanly integrate into your system-wide Ruby include path,
759
755
  # you should put your extension classes inside a custom module.
760
- #
761
- #
756
+ #
757
+ #
762
758
  # Example:
763
- #
759
+ #
764
760
  # ./myldap.rb:
765
761
  # require 'active_ldap'
766
762
  # require 'myldap/user'
767
763
  # require 'myldap/group'
768
764
  # module MyLDAP
769
765
  # end
770
- #
766
+ #
771
767
  # ./myldap/user.rb:
772
768
  # module MyLDAP
773
769
  # class User < ActiveLdap::Base
@@ -775,7 +771,7 @@
775
771
  # belongs_to :groups, :class => 'MyLDAP::Group', :many => 'memberUid'
776
772
  # end
777
773
  # end
778
- #
774
+ #
779
775
  # ./myldap/group.rb:
780
776
  # module MyLDAP
781
777
  # class Group < ActiveLdap::Base
@@ -784,21 +780,21 @@
784
780
  # has_many :primary_members, :class => 'MyLDAP::User', :foreign_key => 'gidNumber', :primary_key => 'gidNumber'
785
781
  # end
786
782
  # end
787
- #
783
+ #
788
784
  # Now in your local applications, you can call
789
- #
785
+ #
790
786
  # require 'myldap'
791
- #
787
+ #
792
788
  # MyLDAP::Group.new('foo')
793
789
  # ...
794
- #
790
+ #
795
791
  # and everything should work well.
796
- #
792
+ #
797
793
  #
798
794
  # ==== force array results for single values
799
795
  #
800
- # Even though Ruby/ActiveLdap attempts to maintain programmatic ease by
801
- # returning Array values only. By specifying 'true' as an argument to
796
+ # Even though Ruby/ActiveLdap attempts to maintain programmatic ease by
797
+ # returning Array values only. By specifying 'true' as an argument to
802
798
  # any attribute method you will get back a Array if it is single value.
803
799
  # Here's an example:
804
800
  #
@@ -808,33 +804,33 @@
808
804
  # => ["Will Drewry"]
809
805
  #
810
806
  # ==== Dynamic attribute crawling
811
- #
812
- # If you use tab completion in irb, you'll notice that you /can/ tab complete the dynamic
813
- # attribute methods. You can still see which methods are for attributes using
807
+ #
808
+ # If you use tab completion in irb, you'll notice that you /can/ tab complete the dynamic
809
+ # attribute methods. You can still see which methods are for attributes using
814
810
  # Base#attribute_names:
815
- #
811
+ #
816
812
  # irb> d = Group.new('develop')
817
813
  # => ...
818
814
  # irb> d.attribute_names
819
815
  # => ["gidNumber", "cn", "memberUid", "commonName", "description", "userPassword", "objectClass"]
820
- #
821
- #
816
+ #
817
+ #
822
818
  # ==== Juggling multiple LDAP connections
823
- #
819
+ #
824
820
  # In the same vein as the last tip, you can use multiple LDAP connections by
825
821
  # per class as follows:
826
- #
822
+ #
827
823
  # irb> anon_class = Class.new(Base)
828
824
  # => ...
829
825
  # irb> anon_class.establish_connection
830
826
  # => ...
831
827
  # irb> auth_class = Class.new(Base)
832
828
  # => ...
833
- # irb> auth_class.establish_connection(password_block => {'mypass'})
829
+ # irb> auth_class.establish_connection(:password_block => {'mypass'})
834
830
  # => ...
835
- #
831
+ #
836
832
  # This can be useful for doing authentication tests and other such tricks.
837
- #
833
+ #
838
834
  # ==== :try_sasl
839
835
  #
840
836
  # If you have the Ruby/LDAP package with the SASL/GSSAPI patch from Ian
@@ -898,7 +894,7 @@
898
894
  # == Limitations
899
895
  #
900
896
  # === Speed
901
- #
897
+ #
902
898
  # Currently, Ruby/ActiveLdap could be faster. I have some recursive type
903
899
  # checking going on which slows object creation down, and I'm sure there
904
900
  # are many, many other places optimizations can be done. Feel free
@@ -911,9 +907,6 @@
911
907
  # package, and I'd like to see it prove helpful to more people than just myself.
912
908
  #
913
909
 
914
- # Blanket warning hiding. Remove for debugging
915
- $VERBOSE, verbose = false, $VERBOSE
916
-
917
910
  if RUBY_PLATFORM.match('linux')
918
911
  require 'active_ldap/timeout'
919
912
  else
@@ -942,14 +935,14 @@ require 'active_ldap/configuration'
942
935
  require 'active_ldap/connection'
943
936
  require 'active_ldap/attributes'
944
937
  require 'active_ldap/object_class'
945
- require 'active_ldap/adaptor/ldap'
938
+ require 'active_ldap/distinguished_name'
946
939
 
947
940
  require_gem_if_need.call("active_record/base", "activerecord")
948
941
  require 'active_ldap/validations'
949
942
  require 'active_ldap/callbacks'
950
943
 
951
944
  module ActiveLdap
952
- VERSION = "0.8.1"
945
+ VERSION = "0.8.2"
953
946
  end
954
947
 
955
948
  ActiveLdap::Base.class_eval do
@@ -962,4 +955,10 @@ ActiveLdap::Base.class_eval do
962
955
  include ActiveLdap::Callbacks
963
956
  end
964
957
 
965
- $VERBOSE = verbose
958
+ unless defined?(ACTIVE_LDAP_CONNECTION_ADAPTERS)
959
+ ACTIVE_LDAP_CONNECTION_ADAPTERS = %w(ldap net_ldap)
960
+ end
961
+
962
+ ACTIVE_LDAP_CONNECTION_ADAPTERS.each do |adapter|
963
+ require "active_ldap/adapter/#{adapter}"
964
+ end