activeldap 5.2.4 → 6.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.yardopts +3 -1
- data/doc/text/development.md +26 -0
- data/doc/text/{news.textile → news.md} +299 -271
- data/doc/text/{rails.textile → rails.md} +35 -33
- data/doc/text/{tutorial.textile → tutorial.md} +177 -182
- data/lib/active_ldap/adapter/base.rb +28 -8
- data/lib/active_ldap/adapter/jndi.rb +4 -6
- data/lib/active_ldap/adapter/jndi_connection.rb +105 -17
- data/lib/active_ldap/adapter/ldap.rb +8 -19
- data/lib/active_ldap/adapter/ldap_ext.rb +32 -13
- data/lib/active_ldap/adapter/net_ldap.rb +9 -18
- data/lib/active_ldap/configuration.rb +24 -1
- data/lib/active_ldap/connection.rb +1 -1
- data/lib/active_ldap/human_readable.rb +5 -4
- data/lib/active_ldap/operations.rb +21 -4
- data/lib/active_ldap/version.rb +1 -1
- data/test/al-test-utils.rb +84 -37
- data/test/test_base.rb +14 -14
- data/test/test_connection.rb +4 -0
- data/test/test_find.rb +12 -2
- data/test/test_supported_control.rb +1 -1
- data/test/test_validation.rb +19 -15
- metadata +13 -15
- data/README.textile +0 -141
- data/doc/text/development.textile +0 -54
@@ -1,26 +1,26 @@
|
|
1
|
-
|
1
|
+
# Rails
|
2
2
|
|
3
3
|
ActiveLdap supports Rails 4.0 or later.
|
4
4
|
|
5
|
-
|
5
|
+
## Install
|
6
6
|
|
7
7
|
To install, simply add the following code to your Gemfile:
|
8
8
|
|
9
|
-
|
9
|
+
```ruby
|
10
10
|
gem 'activeldap', :require => 'active_ldap/railtie'
|
11
|
-
|
11
|
+
```
|
12
12
|
|
13
13
|
You should also depend on an LDAP adapter such as Net::LDAP
|
14
14
|
or Ruby/LDAP. The following example uses Ruby/LDAP:
|
15
15
|
|
16
|
-
|
16
|
+
```ruby
|
17
17
|
gem 'ruby-ldap'
|
18
|
-
|
18
|
+
```
|
19
19
|
|
20
20
|
Bundler will install the gems automatically when you run
|
21
|
-
|
21
|
+
`bundle install`.
|
22
22
|
|
23
|
-
|
23
|
+
## Configuration
|
24
24
|
|
25
25
|
You can use a LDAP configuration per environment. They are in
|
26
26
|
a file named 'ldap.yml' in the config directory of your
|
@@ -32,54 +32,56 @@ development, test, and production environments.
|
|
32
32
|
|
33
33
|
You can generate 'config/ldap.yml' by the following command:
|
34
34
|
|
35
|
-
|
35
|
+
```console
|
36
36
|
% script/rails generate active_ldap:scaffold
|
37
|
-
|
37
|
+
```
|
38
38
|
|
39
39
|
You need to modify 'config/ldap.yml' generated by
|
40
|
-
active_ldap:scaffold
|
40
|
+
`active_ldap:scaffold`. For instance, the development entry
|
41
41
|
would look something like the following:
|
42
42
|
|
43
|
-
|
44
|
-
!!!plain
|
43
|
+
```yaml
|
45
44
|
development:
|
46
45
|
host: 127.0.0.1
|
47
46
|
port: 389
|
48
47
|
base: dc=localhost
|
49
48
|
bind_dn: cn=admin,dc=localhost
|
50
49
|
password: secret
|
51
|
-
|
50
|
+
```
|
52
51
|
|
53
52
|
When your application starts up,
|
54
53
|
ActiveLdap::Base.setup_connection will be called with the
|
55
54
|
parameters specified for your current environment.
|
56
55
|
|
57
56
|
You can replace default orm generators with gems one
|
58
|
-
to skip active_ldap prefix in
|
59
|
-
<pre>config.app_generators.orm :active_ldap</pre>
|
57
|
+
to skip `active_ldap prefix` in `config/application.rb`:
|
60
58
|
|
61
|
-
|
59
|
+
```ruby
|
60
|
+
config.app_generators.orm :active_ldap
|
61
|
+
```
|
62
|
+
|
63
|
+
## Model
|
62
64
|
|
63
65
|
You can generate a User model that represents entries under
|
64
66
|
ou=Users by the following command:
|
65
67
|
|
66
|
-
|
68
|
+
```console
|
67
69
|
% script/rails generate active_ldap:model User --dn-attribute uid --classes person PosixAccount
|
68
|
-
|
70
|
+
```
|
69
71
|
|
70
72
|
It generates the following app/model/user.rb:
|
71
73
|
|
72
|
-
|
74
|
+
```ruby
|
73
75
|
class User < ActiveLdap::Base
|
74
76
|
ldap_mapping :dn_attribute => "uid",
|
75
77
|
:prefix => "ou=Users",
|
76
78
|
:classes => ["person", "PosixAccount"]
|
77
79
|
end
|
78
|
-
|
80
|
+
```
|
79
81
|
|
80
82
|
You can add relationships by modifying app/model/user.rb:
|
81
83
|
|
82
|
-
|
84
|
+
```ruby
|
83
85
|
class User < ActiveLdap::Base
|
84
86
|
ldap_mapping :dn_attribute => 'uid',
|
85
87
|
:prefix => "ou=Users",
|
@@ -91,27 +93,27 @@ class User < ActiveLdap::Base
|
|
91
93
|
belongs_to :groups,
|
92
94
|
:many => 'memberUid'
|
93
95
|
end
|
94
|
-
|
96
|
+
```
|
95
97
|
|
96
98
|
You can also generate a Group model by the following command:
|
97
99
|
|
98
|
-
|
100
|
+
```console
|
99
101
|
% script/rails generate active_ldap:model Group --classes PosixGroup
|
100
|
-
|
102
|
+
```
|
101
103
|
|
102
104
|
app/model/group.rb:
|
103
105
|
|
104
|
-
|
106
|
+
```ruby
|
105
107
|
class Group < ActiveLdap::Base
|
106
108
|
ldap_mapping :dn_attribute => "cn",
|
107
109
|
:prefix => "ou=Groups",
|
108
110
|
:classes => ["PosixGroup"]
|
109
111
|
end
|
110
|
-
|
112
|
+
```
|
111
113
|
|
112
114
|
You can add relationships by modifying app/model/group.rb:
|
113
115
|
|
114
|
-
|
116
|
+
```ruby
|
115
117
|
class Group < ActiveLdap::Base
|
116
118
|
ldap_mapping :dn_attribute => "cn",
|
117
119
|
:prefix => "ou=Groups",
|
@@ -124,18 +126,18 @@ class Group < ActiveLdap::Base
|
|
124
126
|
:foreign_key => "gidNumber",
|
125
127
|
:primary_key => "gidNumber"
|
126
128
|
end
|
127
|
-
|
129
|
+
```
|
128
130
|
|
129
131
|
You can also generate a Ou model by the following command:
|
130
132
|
|
131
|
-
|
133
|
+
```console
|
132
134
|
% script/rails generate active_ldap:model Ou --prefix '' --classes organizationalUnit
|
133
|
-
|
135
|
+
```
|
134
136
|
|
135
|
-
|
137
|
+
```ruby
|
136
138
|
class Ou < ActiveLdap::Base
|
137
139
|
ldap_mapping :dn_attribute => "cn",
|
138
140
|
:prefix => "",
|
139
141
|
:classes => ["organizationalUnit"]
|
140
142
|
end
|
141
|
-
|
143
|
+
```
|
@@ -1,17 +1,18 @@
|
|
1
|
-
|
1
|
+
# Tutorial
|
2
2
|
|
3
|
-
|
3
|
+
## Introduction
|
4
4
|
|
5
|
-
ActiveLdap is a novel way of interacting with LDAP. Most interaction
|
6
|
-
LDAP is done using clunky LDIFs, web interfaces, or with painful
|
7
|
-
required a thick reference manual nearby. ActiveLdap aims to
|
8
|
-
Inspired by
|
9
|
-
|
5
|
+
ActiveLdap is a novel way of interacting with LDAP. Most interaction
|
6
|
+
with LDAP is done using clunky LDIFs, web interfaces, or with painful
|
7
|
+
APIs that required a thick reference manual nearby. ActiveLdap aims to
|
8
|
+
fix that. Inspired by [Active
|
9
|
+
Record](https://rubygems.org/gems/activerecord), ActiveLdap provides
|
10
|
+
an object oriented interface to LDAP entries.
|
10
11
|
|
11
12
|
The target audience is system administrators and LDAP users everywhere that
|
12
13
|
need quick, clean access to LDAP in Ruby.
|
13
14
|
|
14
|
-
|
15
|
+
### What's LDAP?
|
15
16
|
|
16
17
|
LDAP stands for "Lightweight Directory Access Protocol." Basically this means
|
17
18
|
that it is the protocol used for accessing LDAP servers. LDAP servers
|
@@ -23,10 +24,10 @@ authorization server for Unix systems. (Unfortunately, I've yet to try this
|
|
23
24
|
against Microsoft's ActiveDirectory, despite what the name implies.)
|
24
25
|
|
25
26
|
Further reading:
|
26
|
-
*
|
27
|
-
*
|
27
|
+
* [RFC1777](https://tools.ietf.org/html/rfc1777) - Lightweight Directory Access Protocol
|
28
|
+
* [OpenLDAP](https://www.openldap.org)
|
28
29
|
|
29
|
-
|
30
|
+
### So why use ActiveLdap?
|
30
31
|
|
31
32
|
Using LDAP directly (even with the excellent Ruby/LDAP), leaves you bound to
|
32
33
|
the world of the predefined LDAP API. While this API is important for many
|
@@ -35,70 +36,68 @@ arrays of LDAP.mod entries make code harder to read, less intuitive, and just
|
|
35
36
|
less fun to write. Hopefully, ActiveLdap will remedy all of these
|
36
37
|
problems!
|
37
38
|
|
38
|
-
|
39
|
+
## Getting Started
|
39
40
|
|
40
|
-
|
41
|
+
### Requirements
|
41
42
|
|
42
|
-
* A Ruby implementation:
|
43
|
-
* A LDAP library:
|
44
|
-
* A LDAP server:
|
45
|
-
|
43
|
+
* A Ruby implementation: [Ruby](https://www.ruby-lang.org) or [JRuby](https://www.jruby.org/)
|
44
|
+
* A LDAP library: [Ruby/LDAP](https://rubygems.org/gems/ruby-ldap) (for Ruby), [Net::LDAP](https://rubygems.org/gems/net-ldap) (for Ruby or JRuby) or JNDI (for JRuby)
|
45
|
+
* A LDAP server: [OpenLDAP](https://www.openldap.org/), etc
|
46
|
+
* Your LDAP server must allow `root_dse` queries to allow for schema queries
|
46
47
|
|
47
|
-
|
48
|
+
### Installation
|
48
49
|
|
49
50
|
Assuming all the requirements are installed, you can install by gem.
|
50
51
|
|
51
|
-
|
52
|
-
!!!plain
|
52
|
+
```console
|
53
53
|
# gem install activeldap
|
54
|
-
|
54
|
+
```
|
55
55
|
|
56
56
|
Now as a quick test, you can run:
|
57
57
|
|
58
|
-
|
59
|
-
$ irb
|
58
|
+
```console
|
59
|
+
$ irb
|
60
60
|
irb> require 'active_ldap'
|
61
61
|
=> true
|
62
62
|
irb> exit
|
63
|
-
|
63
|
+
```
|
64
64
|
|
65
65
|
If the require returns false or an exception is raised, there has been a
|
66
|
-
problem with the installation.
|
67
|
-
install.
|
66
|
+
problem with the installation.
|
68
67
|
|
69
|
-
|
68
|
+
## Usage
|
70
69
|
|
71
70
|
This section covers using ActiveLdap from writing extension classes to
|
72
71
|
writing applications that use them.
|
73
72
|
|
74
73
|
Just to give a taste of what's to come, here is a quick example using irb:
|
75
74
|
|
76
|
-
|
75
|
+
```text
|
77
76
|
irb> require 'active_ldap'
|
78
|
-
|
77
|
+
```
|
79
78
|
|
80
79
|
Call setup_connection method for connect to LDAP server. In this case, LDAP server
|
81
80
|
is localhost, and base of LDAP tree is "dc=dataspill,dc=org".
|
82
81
|
|
83
|
-
|
82
|
+
```text
|
84
83
|
irb> ActiveLdap::Base.setup_connection :host => 'localhost', :base => 'dc=dataspill,dc=org'
|
85
|
-
|
84
|
+
```
|
86
85
|
|
87
86
|
Here's an extension class that maps to the LDAP Group objects:
|
88
87
|
|
89
|
-
|
88
|
+
```text
|
90
89
|
irb> class Group < ActiveLdap::Base
|
91
90
|
irb* ldap_mapping
|
92
91
|
irb* end
|
93
|
-
|
92
|
+
```
|
94
93
|
|
95
|
-
In the above code, Group class handles sub tree of ou=Groups
|
96
|
-
|
97
|
-
of Group class represents a LDAP object under ou=
|
94
|
+
In the above code, Group class handles sub tree of `ou=Groups`
|
95
|
+
that is `:base` value specified by setup_connection. A instance
|
96
|
+
of Group class represents a LDAP object under `ou=Groups`.
|
98
97
|
|
99
98
|
Here is the Group class in use:
|
100
99
|
|
101
|
-
|
100
|
+
```text
|
102
101
|
# Get all group names
|
103
102
|
irb> all_groups = Group.find(:all, '*').collect {|group| group.cn}
|
104
103
|
=> ["root", "daemon", "bin", "sys", "adm", "tty", ..., "develop"]
|
@@ -114,48 +113,47 @@ irb> group.cn
|
|
114
113
|
# Get gid_number of the develop group
|
115
114
|
irb> group.gid_number
|
116
115
|
=> "1003"
|
117
|
-
|
116
|
+
```
|
118
117
|
|
119
118
|
That's it! No let's get back in to it.
|
120
119
|
|
121
|
-
|
120
|
+
### Extension Classes
|
122
121
|
|
123
122
|
Extension classes are classes that are subclassed from ActiveLdap::Base. They
|
124
123
|
are used to represent objects in your LDAP server abstractly.
|
125
124
|
|
126
|
-
|
125
|
+
#### Why do I need them?
|
127
126
|
|
128
127
|
Extension classes are what make ActiveLdap "active"! They do all the
|
129
128
|
background work to make easy-to-use objects by mapping the LDAP object's
|
130
129
|
attributes on to a Ruby class.
|
131
130
|
|
132
131
|
|
133
|
-
|
132
|
+
#### Special Methods
|
134
133
|
|
135
134
|
I will briefly talk about each of the methods you can use when defining an
|
136
135
|
extension class. In the above example, I only made one special method call
|
137
136
|
inside the Group class. More than likely, you will want to more than that.
|
138
137
|
|
139
|
-
|
138
|
+
##### `ldap_mapping`
|
140
139
|
|
141
140
|
ldap_mapping is the only required method to setup an extension class for use
|
142
141
|
with ActiveLdap. It must be called inside of a subclass as shown above.
|
143
142
|
|
144
143
|
Below is a much more realistic Group class:
|
145
144
|
|
146
|
-
|
145
|
+
```ruby
|
147
146
|
class Group < ActiveLdap::Base
|
148
147
|
ldap_mapping :dn_attribute => 'cn',
|
149
148
|
:prefix => 'ou=Groups', :classes => ['top', 'posixGroup'],
|
150
149
|
:scope => :one
|
151
150
|
end
|
152
|
-
|
151
|
+
```
|
153
152
|
|
154
153
|
As you can see, this method is used for defining how this class maps in to LDAP. Let's say that
|
155
154
|
my LDAP tree looks something like this:
|
156
155
|
|
157
|
-
|
158
|
-
!!!plain
|
156
|
+
```text
|
159
157
|
* dc=dataspill,dc=org
|
160
158
|
|- ou=People,dc=dataspill,dc=org
|
161
159
|
|+ ou=Groups,dc=dataspill,dc=org
|
@@ -163,26 +161,25 @@ my LDAP tree looks something like this:
|
|
163
161
|
|- cn=develop,ou=Groups,dc=dataspill,dc=org
|
164
162
|
|- cn=root,ou=Groups,dc=dataspill,dc=org
|
165
163
|
|- ...
|
166
|
-
|
164
|
+
```
|
167
165
|
|
168
166
|
Under ou=People I store user objects, and under ou=Groups, I store group
|
169
|
-
objects. What
|
170
|
-
abstractly. With the given
|
171
|
-
entries under ou=Groups,dc=dataspill,dc=org using the primary attribute 'cn'
|
167
|
+
objects. What `ldap_mapping` has done is mapped the class in to the LDAP tree
|
168
|
+
abstractly. With the given `:dn_attributes` and `:prefix`, it will only work for
|
169
|
+
entries under `ou=Groups,dc=dataspill,dc=org` using the primary attribute 'cn'
|
172
170
|
as the beginning of the distinguished name.
|
173
171
|
|
174
172
|
Just for clarity, here's how the arguments map out:
|
175
173
|
|
176
|
-
|
177
|
-
!!!plain
|
174
|
+
```text
|
178
175
|
cn=develop,ou=Groups,dc=dataspill,dc=org
|
179
176
|
^^ ^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^
|
180
177
|
:dn_attribute | |
|
181
178
|
:prefix |
|
182
179
|
:base from setup_connection
|
183
|
-
|
180
|
+
```
|
184
181
|
|
185
|
-
|
182
|
+
`:scope` tells ActiveLdap to only search under ou=Groups, and not to look deeper
|
186
183
|
for dn_attribute matches.
|
187
184
|
(e.g. cn=develop,ou=DevGroups,ou=Groups,dc=dataspill,dc=org)
|
188
185
|
You can choose value from between :sub, :one and :base.
|
@@ -209,46 +206,45 @@ case, it would be 'ou=Groups'.
|
|
209
206
|
:prefix.
|
210
207
|
|
211
208
|
|
212
|
-
|
209
|
+
##### `belongs_to`
|
213
210
|
|
214
211
|
This method allows an extension class to make use of other extension classes
|
215
212
|
tying objects together across the LDAP tree. Often, user objects will be
|
216
213
|
members of, or belong_to, Group objects.
|
217
214
|
|
218
|
-
|
219
|
-
!!!plain
|
215
|
+
```text
|
220
216
|
* dc=dataspill,dc=org
|
221
217
|
|+ ou=People,dc=dataspill,dc=org
|
222
218
|
\
|
223
219
|
|- uid=drewry,ou=People,dc=dataspill,dc=org
|
224
220
|
|- ou=Groups,dc=dataspill,dc=org
|
225
|
-
|
221
|
+
```
|
226
222
|
|
227
223
|
|
228
224
|
In the above tree, one such example would be user 'drewry' who is a part of the
|
229
225
|
group 'develop'. You can see this by looking at the 'memberUid' field of 'develop'.
|
230
226
|
|
231
|
-
|
227
|
+
```text
|
232
228
|
irb> develop = Group.find('develop')
|
233
229
|
=> ...
|
234
230
|
irb> develop.memberUid
|
235
231
|
=> ['drewry', 'builder']
|
236
|
-
|
232
|
+
```
|
237
233
|
|
238
234
|
If we look at the LDAP entry for 'drewry', we do not see any references to
|
239
235
|
group 'develop'. In order to remedy that, we can use belongs_to
|
240
236
|
|
241
|
-
|
237
|
+
```text
|
242
238
|
irb> class User < ActiveLdap::Base
|
243
239
|
irb* ldap_mapping :dn_attribute => 'uid', :prefix => 'ou=People', :classes => ['top','account']
|
244
240
|
irb* belongs_to :groups, :class_name => 'Group', :many => 'memberUid', :foreign_key => 'uid'
|
245
241
|
irb* end
|
246
|
-
|
242
|
+
```
|
247
243
|
|
248
244
|
Now, class User will have a method called 'groups' which will retrieve all
|
249
245
|
Group objects that a user is in.
|
250
246
|
|
251
|
-
|
247
|
+
```text
|
252
248
|
irb> me = User.find('drewry')
|
253
249
|
irb> me.groups
|
254
250
|
=> #<ActiveLdap::Association::BelongsToMany...> # Enumerable object
|
@@ -258,22 +254,22 @@ irb> me.groups.each { |group| p group.cn };nil
|
|
258
254
|
"develop"
|
259
255
|
=> nil
|
260
256
|
(Note: nil is just there to make the output cleaner...)
|
261
|
-
|
257
|
+
```
|
262
258
|
|
263
259
|
TIP: If you weren't sure what the distinguished name attribute was for Group,
|
264
260
|
you could also do the following:
|
265
261
|
|
266
|
-
|
262
|
+
```text
|
267
263
|
irb> me.groups.each { |group| p group.id };nil
|
268
264
|
"cdrom"
|
269
265
|
"audio"
|
270
266
|
"develop"
|
271
267
|
=> nil
|
272
|
-
|
268
|
+
```
|
273
269
|
|
274
270
|
Now let's talk about the arguments of belongs_to. We use the following code that extends Group group a bit for explain:
|
275
271
|
|
276
|
-
|
272
|
+
```ruby
|
277
273
|
class User < ActiveLdap::Base
|
278
274
|
ldap_mapping :dn_attribute => 'uid', :prefix => 'People', :classes => ['top','account']
|
279
275
|
|
@@ -285,42 +281,42 @@ class User < ActiveLdap::Base
|
|
285
281
|
belongs_to :groups, :foreign_key => 'uid',
|
286
282
|
:class_name => 'Group', :many => 'memberUid',
|
287
283
|
end
|
288
|
-
|
284
|
+
```
|
289
285
|
|
290
286
|
The first argument is the name of the method you wish to create. In this case, we created a method called primary_group and groups using the symbol :primary_group and :groups. The next collection of arguments are actually a Hash (as with ldap_mapping).
|
291
287
|
|
292
|
-
|
288
|
+
`:foreign_key` tells `belongs_to` what attribute Group objects have that match the related object's attribute. If `:foreign_key` is left off of the argument list, it is assumed to be the dn_attribute.
|
293
289
|
|
294
290
|
In the example, uid is used for :foreign_key. It may confuse you.
|
295
291
|
|
296
|
-
ActiveLdap uses
|
297
|
-
may not be "foreign key". You can consider
|
292
|
+
ActiveLdap uses `:foreign_key` as "own attribute name". So it
|
293
|
+
may not be "foreign key". You can consider `:foreign_key` just
|
298
294
|
as a relation key.
|
299
295
|
|
300
|
-
|
296
|
+
`:primary_key` is treated as "related object's attribute name"
|
301
297
|
as we discussed later.
|
302
298
|
|
303
|
-
|
299
|
+
`:class_name` should be a string that has the name of a class
|
304
300
|
you've already included. If your class is inside of a module,
|
305
301
|
be sure to put the whole name, e.g.
|
306
|
-
|
302
|
+
`:class_name => "MyLdapModule::Group"`.
|
307
303
|
|
308
|
-
|
304
|
+
`:many` and `:primary_key` are similar. Both of them specifies attribute name of related object specified by `:foreign_key`. Those values are attribute name that can be used by object of class specified by `:class_name`.
|
309
305
|
|
310
|
-
Relation is resolved by searching entries of
|
306
|
+
Relation is resolved by searching entries of `:class_name` class with `:foreign_key` attribute value. Search target attribute for it is `:primary_key` or `:many`. primary_group method in the above example searches Group objects with User object's gidNumber value as Group object's gidNumber value. Matched Group objects are belonged objects.
|
311
307
|
|
312
|
-
|
308
|
+
`:parimary_key` is used for an object just belongs to an object. The first matched object is treated as beloned object.
|
313
309
|
|
314
|
-
|
310
|
+
`:many` is used for an object belongs to many objects. All of matched objects are treated as belonged objects.
|
315
311
|
|
316
|
-
|
312
|
+
##### `has_many`
|
317
313
|
|
318
314
|
This method is the opposite of belongs_to. Instead of checking other objects in
|
319
315
|
other parts of the LDAP tree to see if you belong to them, you have multiple
|
320
316
|
objects from other trees listed in your object. To show this, we can just
|
321
317
|
invert the example from above:
|
322
318
|
|
323
|
-
|
319
|
+
```ruby
|
324
320
|
class Group < ActiveLdap::Base
|
325
321
|
ldap_mapping :dn_attribute => 'cn', :prefix => 'ou=Groups', :classes => ['top', 'posixGroup']
|
326
322
|
|
@@ -332,104 +328,104 @@ class Group < ActiveLdap::Base
|
|
332
328
|
has_many :members, :wrap => "memberUid",
|
333
329
|
:class_name => "User", :primary_key => 'uid'
|
334
330
|
end
|
335
|
-
|
331
|
+
```
|
336
332
|
|
337
333
|
Now we can see that group develop has user 'drewry' as a member, and it can
|
338
|
-
even return all responses in object form just like belongs_to methods.
|
334
|
+
even return all responses in object form just like `belongs_to` methods.
|
339
335
|
|
340
|
-
|
336
|
+
```text
|
341
337
|
irb> develop = Group.find('develop')
|
342
338
|
=> ...
|
343
339
|
irb> develop.members
|
344
340
|
=> #<ActiveLdap::Association::HasManyWrap:..> # Enumerable object
|
345
341
|
irb> develop.members.map{|member| member.id}
|
346
342
|
=> ["drewry", "builder"]
|
347
|
-
|
343
|
+
```
|
348
344
|
|
349
|
-
The arguments for has_many follow the exact same idea that belongs_to's
|
345
|
+
The arguments for `has_many` follow the exact same idea that `belongs_to`'s
|
350
346
|
arguments followed. :wrap's contents are used to search for matching
|
351
|
-
|
352
|
-
dn_attribute of the specified
|
347
|
+
`:primary_key` content. If `:primary_key` is not specified, it defaults to the
|
348
|
+
dn_attribute of the specified `:class_name`.
|
353
349
|
|
354
|
-
|
350
|
+
### Using these new classes
|
355
351
|
|
356
352
|
These new classes have many method calls. Many of them are automatically
|
357
353
|
generated to provide access to the LDAP object's attributes. Other were defined
|
358
|
-
during class creation by special methods like belongs_to
|
354
|
+
during class creation by special methods like `belongs_to`. There are a few other
|
359
355
|
methods that do not fall in to these categories.
|
360
356
|
|
361
|
-
|
357
|
+
#### `.find`
|
362
358
|
|
363
|
-
|
359
|
+
`.find` is a class method that is accessible from
|
364
360
|
any subclass of Base that has 'ldap_mapping' called. When
|
365
|
-
called
|
361
|
+
called `.first(:first)` returns the first match of the given class.
|
366
362
|
|
367
|
-
|
363
|
+
```text
|
368
364
|
irb> Group.find(:first, 'deve*").cn
|
369
365
|
=> "develop"
|
370
|
-
|
366
|
+
```
|
371
367
|
|
372
368
|
In this simple example, Group.find took the search string of 'deve*' and
|
373
369
|
searched for the first match in Group where the dn_attribute matched the
|
374
370
|
query. This is the simplest example of .find.
|
375
371
|
|
376
|
-
|
372
|
+
```text
|
377
373
|
irb> Group.find(:all).collect {|group| group.cn}
|
378
374
|
=> ["root", "daemon", "bin", "sys", "adm", "tty", ..., "develop"]
|
379
|
-
|
375
|
+
```
|
380
376
|
|
381
377
|
Here .find(:all) returns all matches to the same query. Both .find(:first) and
|
382
378
|
.find(:all) also can take more expressive arguments:
|
383
379
|
|
384
|
-
|
380
|
+
```text
|
385
381
|
irb> Group.find(:all, :attribute => 'gidNumber', :value => '1003').collect {|group| group.cn}
|
386
382
|
=> ["develop"]
|
387
|
-
|
383
|
+
```
|
388
384
|
|
389
385
|
So it is pretty clear what :attribute and :value do - they are used to query as
|
390
|
-
|
386
|
+
`:attribute=:value`.
|
391
387
|
|
392
388
|
If :attribute is unspecified, it defaults to the dn_attribute.
|
393
389
|
|
394
390
|
It is also possible to override :attribute and :value by specifying :filter. This
|
395
391
|
argument allows the direct specification of a LDAP filter to retrieve objects by.
|
396
392
|
|
397
|
-
|
393
|
+
##### Using the :filter option
|
398
394
|
|
399
395
|
The filter option lets you pass in an LDAP query string.
|
400
396
|
For example retrieving all groups with cn which starts with @'dev'@ and has @guid@ == 1:
|
401
397
|
|
402
|
-
|
398
|
+
```text
|
403
399
|
irb> Group.find(:all, :filter => '(&(cn=dev*)(guid=1))').collect {|group| group.cn}
|
404
400
|
=> ["develop"]
|
405
|
-
|
401
|
+
```
|
406
402
|
|
407
403
|
It also allows a hash like sintax (sparing you the need to write the query by hand ):
|
408
404
|
|
409
|
-
|
405
|
+
```text
|
410
406
|
irb> Group.find(:all, :filter => {:cn => 'dev*', :guid => 1 }).collect {|group| group.cn}
|
411
407
|
=> ["develop", "developers", "sys", "sysadmin"]
|
412
|
-
|
408
|
+
```
|
413
409
|
|
414
410
|
You can build complex queries combining the hash syntax with arrays and @:or@ and @:and@ operators retrieving all users whose name contains 'john' or cn ends with 'smith' or contains 'liz'
|
415
411
|
|
416
|
-
|
412
|
+
```text
|
417
413
|
irb> User.find(:all, filter: [:or, [:or, { :cn => '*smith', :name => '*john*'} ], { cn: '*liz*' }]).collect(&:cn)
|
418
414
|
=> ['john.smith', 'jane.smith', 'john tha ripper', 'liz.taylor', ...]
|
419
|
-
|
415
|
+
```
|
420
416
|
|
421
|
-
|
417
|
+
#### .search
|
422
418
|
|
423
419
|
.search is a class method that is accessible from any subclass of Base, and Base.
|
424
420
|
It lets the user perform an arbitrary search against the current LDAP connection
|
425
421
|
irrespetive of LDAP mapping data. This is meant to be useful as a utility method
|
426
422
|
to cover 80% of the cases where a user would want to use Base.connection directly.
|
427
423
|
|
428
|
-
|
424
|
+
```text
|
429
425
|
irb> Base.search(:base => 'dc=example,dc=com', :filter => '(uid=roo*)',
|
430
426
|
:scope => :sub, :attributes => ['uid', 'cn'])
|
431
427
|
=> [["uid=root,ou=People,dc=dataspill,dc=org",{"cn"=>["root"], "uidNumber"=>["0"]}]
|
432
|
-
|
428
|
+
```
|
433
429
|
|
434
430
|
You can specify the :filter, :base, :scope, and :attributes, but they all have defaults --
|
435
431
|
* :filter defaults to objectClass=* - usually this isn't what you want
|
@@ -437,41 +433,41 @@ You can specify the :filter, :base, :scope, and :attributes, but they all have d
|
|
437
433
|
* :scope defaults to :sub. Usually you won't need to change it (You can choose value also from between :one and :base)
|
438
434
|
* :attributes defaults to [] and is the list of attributes you want back. Empty means all of them.
|
439
435
|
|
440
|
-
|
436
|
+
#### #valid?
|
441
437
|
|
442
438
|
valid? is a method that verifies that all attributes that are required by the
|
443
439
|
objects current objectClasses are populated.
|
444
440
|
|
445
|
-
|
441
|
+
#### #save
|
446
442
|
|
447
443
|
save is a method that writes any changes to an object back to the LDAP server.
|
448
444
|
It automatically handles the addition of new objects, and the modification of
|
449
445
|
existing ones.
|
450
446
|
|
451
|
-
|
447
|
+
#### .exists?
|
452
448
|
|
453
449
|
exists? is a simple method which returns true is the current object exists in
|
454
450
|
LDAP, or false if it does not.
|
455
451
|
|
456
|
-
|
452
|
+
```text
|
457
453
|
irb> User.exists?("dshadsadsa")
|
458
454
|
=> false
|
459
|
-
|
455
|
+
```
|
460
456
|
|
461
457
|
|
462
|
-
|
458
|
+
### ActiveLdap::Base
|
463
459
|
|
464
460
|
ActiveLdap::Base has come up a number of times in the examples above. Every
|
465
461
|
time, it was being used as the super class for the wrapper objects. While this
|
466
462
|
is it's main purpose, it also handles quite a bit more in the background.
|
467
463
|
|
468
|
-
|
464
|
+
#### What is it?
|
469
465
|
|
470
466
|
ActiveLdap::Base is the heart of ActiveLdap. It does all the schema
|
471
467
|
parsing for validation and attribute-to-method mangling as well as manage the
|
472
468
|
connection to LDAP.
|
473
469
|
|
474
|
-
|
470
|
+
##### setup_connection
|
475
471
|
|
476
472
|
Base.setup_connection takes many (optional) arguments and is used to
|
477
473
|
connect to the LDAP server. Sometimes you will want to connect anonymously
|
@@ -485,7 +481,7 @@ server allows anonymous binding, and you only want to access data in a
|
|
485
481
|
read-only fashion, you won't need to call Base.setup_connection. Here
|
486
482
|
is a fully parameterized call:
|
487
483
|
|
488
|
-
|
484
|
+
```ruby
|
489
485
|
Base.setup_connection(
|
490
486
|
:host => 'ldap.dataspill.org',
|
491
487
|
:port => 389,
|
@@ -496,7 +492,7 @@ Base.setup_connection(
|
|
496
492
|
:allow_anonymous => false,
|
497
493
|
:try_sasl => false
|
498
494
|
)
|
499
|
-
|
495
|
+
```
|
500
496
|
|
501
497
|
There are quite a few arguments, but luckily many of them have safe defaults:
|
502
498
|
* :host defaults to "127.0.0.1".
|
@@ -550,51 +546,51 @@ in an internal class variable which is used to cache the
|
|
550
546
|
information without ditching the defaults passed in from
|
551
547
|
configuration.rb
|
552
548
|
|
553
|
-
|
549
|
+
##### connection
|
554
550
|
|
555
551
|
Base.connection returns the ActiveLdap::Connection object.
|
556
552
|
|
557
|
-
|
553
|
+
### Exceptions
|
558
554
|
|
559
555
|
There are a few custom exceptions used in ActiveLdap. They are detailed below.
|
560
556
|
|
561
|
-
|
557
|
+
#### DeleteError
|
562
558
|
|
563
559
|
This exception is raised when #delete fails. It will include LDAP error
|
564
560
|
information that was passed up during the error.
|
565
561
|
|
566
|
-
|
562
|
+
#### SaveError
|
567
563
|
|
568
564
|
This exception is raised when there is a problem in #save updating or creating
|
569
565
|
an LDAP entry. Often the error messages are cryptic. Looking at the server
|
570
566
|
logs or doing an "Wireshark":http://www.wireshark.org dump of the connection will
|
571
567
|
often provide better insight.
|
572
568
|
|
573
|
-
|
569
|
+
#### AuthenticationError
|
574
570
|
|
575
571
|
This exception is raised during Base.setup_connection if no valid authentication methods
|
576
572
|
succeeded.
|
577
573
|
|
578
|
-
|
574
|
+
#### ConnectionError
|
579
575
|
|
580
576
|
This exception is raised during Base.setup_connection if no valid
|
581
577
|
connection to the LDAP server could be created. Check you
|
582
578
|
Base.setup_connection arguments, and network connectivity! Also check
|
583
579
|
your LDAP server logs to see if it ever saw the request.
|
584
580
|
|
585
|
-
|
581
|
+
#### ObjectClassError
|
586
582
|
|
587
583
|
This exception is raised when an object class is used that is not defined
|
588
584
|
in the schema.
|
589
585
|
|
590
|
-
|
586
|
+
### Others
|
591
587
|
|
592
588
|
Other exceptions may be raised by the Ruby/LDAP module, or by other subsystems.
|
593
589
|
If you get one of these exceptions and think it should be wrapped, write me an
|
594
590
|
email and let me know where it is and what you expected. For faster results,
|
595
591
|
email a patch!
|
596
592
|
|
597
|
-
|
593
|
+
### Putting it all together
|
598
594
|
|
599
595
|
Now that all of the components of ActiveLdap have been covered, it's time
|
600
596
|
to put it all together! The rest of this section will show the steps to setup
|
@@ -603,43 +599,42 @@ above.
|
|
603
599
|
|
604
600
|
All of the scripts here are in the package's examples/ directory.
|
605
601
|
|
606
|
-
|
602
|
+
#### Setting up
|
607
603
|
|
608
604
|
Create directory for scripts.
|
609
605
|
|
610
|
-
|
611
|
-
!!!plain
|
606
|
+
```console
|
612
607
|
% mkdir -p ldapadmin/objects
|
613
|
-
|
608
|
+
```
|
614
609
|
|
615
610
|
In ldapadmin/objects/ create the file user.rb:
|
616
611
|
|
617
|
-
|
612
|
+
```ruby
|
618
613
|
require 'objects/group'
|
619
614
|
|
620
615
|
class User < ActiveLdap::Base
|
621
616
|
ldap_mapping :dn_attribute => 'uid', :prefix => 'ou=People', :classes => ['person', 'posixAccount']
|
622
617
|
belongs_to :groups, :class_name => 'Group', :many => 'memberUid'
|
623
618
|
end
|
624
|
-
|
619
|
+
```
|
625
620
|
|
626
621
|
In ldapadmin/objects/ create the file group.rb:
|
627
622
|
|
628
|
-
|
623
|
+
```ruby
|
629
624
|
class Group < ActiveLdap::Base
|
630
625
|
ldap_mapping :classes => ['top', 'posixGroup'], :prefix => 'ou=Groups'
|
631
626
|
has_many :members, :class_name => "User", :wrap => "memberUid"
|
632
627
|
has_many :primary_members, :class_name => 'User', :foreign_key => 'gidNumber', :primary_key => 'gidNumber'
|
633
628
|
end
|
634
|
-
|
629
|
+
```
|
635
630
|
|
636
631
|
Now, we can write some small scripts to do simple management tasks.
|
637
632
|
|
638
|
-
|
633
|
+
#### Creating LDAP entries
|
639
634
|
|
640
635
|
Now let's create a really dumb script for adding users - ldapadmin/useradd:
|
641
636
|
|
642
|
-
|
637
|
+
```ruby
|
643
638
|
#!/usr/bin/ruby -W0
|
644
639
|
|
645
640
|
base = File.expand_path(File.join(File.dirname(__FILE__), ".."))
|
@@ -686,13 +681,13 @@ unless user.save
|
|
686
681
|
puts user.errors.full_messages
|
687
682
|
exit 1
|
688
683
|
end
|
689
|
-
|
684
|
+
```
|
690
685
|
|
691
|
-
|
686
|
+
#### Managing LDAP entries
|
692
687
|
|
693
688
|
Now let's create another dumb script for modifying users - ldapadmin/usermod:
|
694
689
|
|
695
|
-
|
690
|
+
```ruby
|
696
691
|
#!/usr/bin/ruby -W0
|
697
692
|
|
698
693
|
base = File.expand_path(File.join(File.dirname(__FILE__), ".."))
|
@@ -736,13 +731,13 @@ unless user.save
|
|
736
731
|
puts user.errors.full_messages
|
737
732
|
exit 1
|
738
733
|
end
|
739
|
-
|
734
|
+
```
|
740
735
|
|
741
|
-
|
736
|
+
#### Removing LDAP entries
|
742
737
|
|
743
738
|
Now let's create more one for deleting users - ldapadmin/userdel:
|
744
739
|
|
745
|
-
|
740
|
+
```ruby
|
746
741
|
#!/usr/bin/ruby -W0
|
747
742
|
|
748
743
|
base = File.expand_path(File.join(File.dirname(__FILE__), ".."))
|
@@ -778,20 +773,20 @@ unless User.exists?(name)
|
|
778
773
|
end
|
779
774
|
|
780
775
|
User.destroy(name)
|
781
|
-
|
776
|
+
```
|
782
777
|
|
783
|
-
|
778
|
+
### Advanced Topics
|
784
779
|
|
785
780
|
Below are some situation tips and tricks to get the most out of ActiveLdap.
|
786
781
|
|
787
782
|
|
788
|
-
|
783
|
+
#### Binary data and other subtypes
|
789
784
|
|
790
785
|
Sometimes, you may want to store attributes with language specifiers, or
|
791
786
|
perhaps in binary form. This is (finally!) fully supported. To do so,
|
792
787
|
follow the examples below:
|
793
788
|
|
794
|
-
|
789
|
+
```text
|
795
790
|
irb> user = User.new('drewry')
|
796
791
|
=> ...
|
797
792
|
# This adds a cn entry in lang-en and whatever the server default is.
|
@@ -803,7 +798,7 @@ irb> user.cn
|
|
803
798
|
irb> user.user_certificate = File.read('example.der')
|
804
799
|
=> ...
|
805
800
|
irb> user.save
|
806
|
-
|
801
|
+
```
|
807
802
|
|
808
803
|
So that's a lot to take in. Here's what is going on. I just set the LDAP
|
809
804
|
object's cn to "wad" and cn:lang-en-us to ["wad", "Will Drewry"].
|
@@ -815,9 +810,9 @@ get wrapped in @{'binary' => value}@ if you don't do it. This keeps your #writes
|
|
815
810
|
from breaking, and my code from crying. For correctness, I could have easily
|
816
811
|
done the following:
|
817
812
|
|
818
|
-
|
813
|
+
```text
|
819
814
|
irb> user.user_certificate = {'binary' => File.read('example.der')}
|
820
|
-
|
815
|
+
```
|
821
816
|
|
822
817
|
You should note that some binary data does not use the binary subtype all the time.
|
823
818
|
One example is jpegPhoto. You can use it as jpegPhoto;binary or just as jpegPhoto.
|
@@ -829,9 +824,9 @@ LDAP site policy and not by any programmatic means.
|
|
829
824
|
The only subtypes defined in LDAPv3 are lang-* and binary. These can be nested
|
830
825
|
though:
|
831
826
|
|
832
|
-
|
827
|
+
```text
|
833
828
|
irb> user.cn = [{'lang-ja' => {'binary' => 'some Japanese'}}]
|
834
|
-
|
829
|
+
```
|
835
830
|
|
836
831
|
As I understand it, OpenLDAP does not support nested subtypes, but some
|
837
832
|
documentation I've read suggests that Netscape's LDAP server does. I only
|
@@ -841,7 +836,7 @@ goes!
|
|
841
836
|
|
842
837
|
And that pretty much wraps up this section.
|
843
838
|
|
844
|
-
|
839
|
+
#### Further integration with your environment aka namespacing
|
845
840
|
|
846
841
|
If you want this to cleanly integrate into your system-wide Ruby include path,
|
847
842
|
you should put your extension classes inside a custom module.
|
@@ -851,28 +846,28 @@ Example:
|
|
851
846
|
|
852
847
|
./myldap.rb:
|
853
848
|
|
854
|
-
|
849
|
+
```ruby
|
855
850
|
require 'active_ldap'
|
856
851
|
require 'myldap/user'
|
857
852
|
require 'myldap/group'
|
858
853
|
module MyLDAP
|
859
854
|
end
|
860
|
-
|
855
|
+
```
|
861
856
|
|
862
857
|
./myldap/user.rb:
|
863
858
|
|
864
|
-
|
859
|
+
```ruby
|
865
860
|
module MyLDAP
|
866
861
|
class User < ActiveLdap::Base
|
867
862
|
ldap_mapping :dn_attribute => 'uid', :prefix => 'ou=People', :classes => ['top', 'account', 'posixAccount']
|
868
863
|
belongs_to :groups, :class_name => 'MyLDAP::Group', :many => 'memberUid'
|
869
864
|
end
|
870
865
|
end
|
871
|
-
|
866
|
+
```
|
872
867
|
|
873
868
|
./myldap/group.rb:
|
874
869
|
|
875
|
-
|
870
|
+
```ruby
|
876
871
|
module MyLDAP
|
877
872
|
class Group < ActiveLdap::Base
|
878
873
|
ldap_mapping :classes => ['top', 'posixGroup'], :prefix => 'ou=Groups'
|
@@ -880,54 +875,54 @@ module MyLDAP
|
|
880
875
|
has_many :primary_members, :class_name => 'MyLDAP::User', :foreign_key => 'gidNumber', :primary_key => 'gidNumber'
|
881
876
|
end
|
882
877
|
end
|
883
|
-
|
878
|
+
```
|
884
879
|
|
885
880
|
Now in your local applications, you can call
|
886
881
|
|
887
|
-
|
882
|
+
```ruby
|
888
883
|
require 'myldap'
|
889
884
|
|
890
885
|
MyLDAP::Group.new('foo')
|
891
886
|
...
|
892
|
-
|
887
|
+
```
|
893
888
|
|
894
889
|
and everything should work well.
|
895
890
|
|
896
891
|
|
897
|
-
|
892
|
+
#### force array results for single values
|
898
893
|
|
899
894
|
Even though ActiveLdap attempts to maintain programmatic ease by
|
900
895
|
returning Array values only. By specifying 'true' as an argument to
|
901
896
|
any attribute method you will get back a Array if it is single value.
|
902
897
|
Here's an example:
|
903
898
|
|
904
|
-
|
899
|
+
```text
|
905
900
|
irb> user = User.new('drewry')
|
906
901
|
=> ...
|
907
902
|
irb> user.cn(true)
|
908
903
|
=> ["Will Drewry"]
|
909
|
-
|
904
|
+
```
|
910
905
|
|
911
|
-
|
906
|
+
#### Dynamic attribute crawling
|
912
907
|
|
913
908
|
If you use tab completion in irb, you'll notice that you /can/ tab complete the dynamic
|
914
909
|
attribute methods. You can still see which methods are for attributes using
|
915
910
|
Base#attribute_names:
|
916
911
|
|
917
|
-
|
912
|
+
```text
|
918
913
|
irb> d = Group.new('develop')
|
919
914
|
=> ...
|
920
915
|
irb> d.attribute_names
|
921
916
|
=> ["gidNumber", "cn", "memberUid", "commonName", "description", "userPassword", "objectClass"]
|
922
|
-
|
917
|
+
```
|
923
918
|
|
924
919
|
|
925
|
-
|
920
|
+
#### Juggling multiple LDAP connections
|
926
921
|
|
927
922
|
In the same vein as the last tip, you can use multiple LDAP connections by
|
928
923
|
per class as follows:
|
929
924
|
|
930
|
-
|
925
|
+
```text
|
931
926
|
irb> anon_class = Class.new(Base)
|
932
927
|
=> ...
|
933
928
|
irb> anon_class.setup_connection
|
@@ -936,11 +931,11 @@ irb> auth_class = Class.new(Base)
|
|
936
931
|
=> ...
|
937
932
|
irb> auth_class.setup_connection(:password_block => lambda{'mypass'})
|
938
933
|
=> ...
|
939
|
-
|
934
|
+
```
|
940
935
|
|
941
936
|
This can be useful for doing authentication tests and other such tricks.
|
942
937
|
|
943
|
-
|
938
|
+
#### :try_sasl
|
944
939
|
|
945
940
|
If you have the Ruby/LDAP package with the SASL/GSSAPI patch from Ian
|
946
941
|
MacDonald's web site, you can use Kerberos to bind to your LDAP server. By
|
@@ -949,7 +944,7 @@ default, :try_sasl is false.
|
|
949
944
|
Also note that you must be using OpenLDAP 2.1.29 or higher to use SASL/GSSAPI
|
950
945
|
due to some bugs in older versions of OpenLDAP.
|
951
946
|
|
952
|
-
|
947
|
+
#### Don't be afraid! [Internals]
|
953
948
|
|
954
949
|
Don't be afraid to add more methods to the extensions classes and to
|
955
950
|
experiment. That's exactly how I ended up with this package. If you come up
|
@@ -959,7 +954,7 @@ The internal structure of ActiveLdap::Base, and thus all its subclasses, is
|
|
959
954
|
still in flux. I've tried to minimize the changes to the overall API, but
|
960
955
|
the internals are still rough around the edges.
|
961
956
|
|
962
|
-
|
957
|
+
##### Where's ldap_mapping data stored? How can I get to it?
|
963
958
|
|
964
959
|
When you call ldap_mapping, it overwrites several class methods inherited
|
965
960
|
from Base:
|
@@ -974,7 +969,7 @@ from any new instance methods you define:
|
|
974
969
|
* Base#required_classes()
|
975
970
|
* Base#dn_attribute()
|
976
971
|
|
977
|
-
|
972
|
+
##### What else?
|
978
973
|
|
979
974
|
Well if you want to use the LDAP connection for anything, I'd suggest still
|
980
975
|
calling Base.connection to get it. There really aren't many other internals
|
@@ -987,12 +982,12 @@ any methods you write might need to figure it out. I'd suggest just
|
|
987
982
|
calling self[attribname] to get the value, but if that's not good enough,
|
988
983
|
you can call look up the stored name by #to_real_attribute_name as follows:
|
989
984
|
|
990
|
-
|
985
|
+
```text
|
991
986
|
irb> User.find(:first).instance_eval do
|
992
987
|
irb> to_real_attribute_name('commonName')
|
993
988
|
irb> end
|
994
989
|
=> 'cn'
|
995
|
-
|
990
|
+
```
|
996
991
|
|
997
992
|
This tells you the name the attribute is stored in behind the scenes (@data).
|
998
993
|
Again, self[attribname] should be enough for most extensions, but if not,
|
@@ -1001,16 +996,16 @@ it's probably safe to dabble here.
|
|
1001
996
|
Also, if you like to look up all aliases for an attribute, you can call the
|
1002
997
|
following:
|
1003
998
|
|
1004
|
-
|
999
|
+
```text
|
1005
1000
|
irb> User.schema.attribute_type 'cn', 'NAME'
|
1006
1001
|
=> ["cn", "commonName"]
|
1007
|
-
|
1002
|
+
```
|
1008
1003
|
|
1009
1004
|
This is discovered automagically from the LDAP server's schema.
|
1010
1005
|
|
1011
|
-
|
1006
|
+
## Limitations
|
1012
1007
|
|
1013
|
-
|
1008
|
+
### Speed
|
1014
1009
|
|
1015
1010
|
Currently, ActiveLdap could be faster. I have some recursive type
|
1016
1011
|
checking going on which slows object creation down, and I'm sure there
|
@@ -1018,7 +1013,7 @@ are many, many other places optimizations can be done. Feel free
|
|
1018
1013
|
to send patches, or just hang in there until I can optimize away the
|
1019
1014
|
slowness.
|
1020
1015
|
|
1021
|
-
|
1016
|
+
## Feedback
|
1022
1017
|
|
1023
1018
|
Any and all feedback and patches are welcome. I am very excited about this
|
1024
1019
|
package, and I'd like to see it prove helpful to more people than just myself.
|