ruby-activeldap 0.8.1 → 0.8.2

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 (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