ucb_ldap 1.3.2 → 1.4.2
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +5 -0
- data/Manifest +1 -1
- data/README +5 -5
- data/Rakefile +2 -2
- data/TODO +1 -1
- data/lib/person/affiliation_methods.rb +22 -9
- data/lib/ucb_ldap.rb +55 -58
- data/lib/ucb_ldap_entry.rb +96 -26
- data/lib/ucb_ldap_namespace.rb +17 -9
- data/lib/ucb_ldap_org.rb +130 -70
- data/lib/ucb_ldap_person.rb +26 -13
- data/lib/ucb_ldap_service.rb +4 -2
- data/schema/schema.yml +135 -2
- data/ucb_ldap.gemspec +9 -13
- data/version.yml +1 -1
- metadata +32 -25
- data/init.rb +0 -1
data/CHANGELOG
CHANGED
@@ -1,5 +1,10 @@
|
|
1
1
|
= UCB::LDAP Changelog
|
2
2
|
|
3
|
+
== Version 1.4.1
|
4
|
+
* Remove hack that tried to persist the net-ldap connection instance as this cause problems
|
5
|
+
with leaving countless file descriptors open when run under JRuby.
|
6
|
+
* Updated bundled schema.yml file
|
7
|
+
|
3
8
|
== Version 1.2.1, January 22, 2008
|
4
9
|
|
5
10
|
* fixed bug: include UCB::LDAP call at top level that corrupted namespace
|
data/Manifest
CHANGED
@@ -3,7 +3,6 @@ Manifest
|
|
3
3
|
README
|
4
4
|
Rakefile
|
5
5
|
TODO
|
6
|
-
init.rb
|
7
6
|
lib/person/adv_con_person.rb
|
8
7
|
lib/person/affiliation_methods.rb
|
9
8
|
lib/person/generic_attributes.rb
|
@@ -21,4 +20,5 @@ lib/ucb_ldap_schema_attribute.rb
|
|
21
20
|
lib/ucb_ldap_service.rb
|
22
21
|
lib/ucb_ldap_student_term.rb
|
23
22
|
schema/schema.yml
|
23
|
+
ucb_ldap.gemspec
|
24
24
|
version.yml
|
data/README
CHANGED
@@ -5,7 +5,7 @@ LDAP directory: http://directory.berkeley.edu
|
|
5
5
|
|
6
6
|
==Introduction to LDAP
|
7
7
|
If you are blissfully ignorant of LDAP, you should familiarize yourself with some of the basics.
|
8
|
-
Here is a great online resource: http://www.zytrax.com/books/ldap
|
8
|
+
Here is a great online resource: http://www.zytrax.com/books/ldap
|
9
9
|
|
10
10
|
The RDoc for the ruby-net-ldap Gem (http://rubyfurnace.com/docs/ruby-net-ldap-0.0.4/classes/Net/LDAP.html) also has a good introduction to LDAP.
|
11
11
|
|
@@ -29,7 +29,7 @@ See UCB::LDAP::Entry for more information.
|
|
29
29
|
|
30
30
|
Search the Person tree getting back UCB::LDAP::Person instances:
|
31
31
|
|
32
|
-
person = UCB::LDAP::Person.
|
32
|
+
person = UCB::LDAP::Person.find_by_uid("123")
|
33
33
|
|
34
34
|
person.firstname #=> "John"
|
35
35
|
person.affiliations #=> ['EMPLOYEE-TYPE-STAFF']
|
@@ -56,11 +56,11 @@ See UCB::LDAP::Org for more information.
|
|
56
56
|
If you want access the directory anonomously, no credentials are required.
|
57
57
|
If you want to access via a privileged bind, authenticate before querying:
|
58
58
|
|
59
|
-
p = UCB::LDAP::Person.
|
59
|
+
p = UCB::LDAP::Person.find_by_uid("123")
|
60
60
|
p.non_public_attr #=> NoMethodError
|
61
61
|
|
62
62
|
UCB::LDAP.authenticate("mybind", "mypassword")
|
63
|
-
p = UCB::LDAP::Person.
|
63
|
+
p = UCB::LDAP::Person.find_by_uid("123")
|
64
64
|
p.non_public_attr #=> "some value"
|
65
65
|
|
66
66
|
=== Privileged Binds and Rails
|
@@ -70,7 +70,7 @@ See UCB::LDAP.bind_for_rails()
|
|
70
70
|
==Dependencies
|
71
71
|
|
72
72
|
* Net::LDAP
|
73
|
-
* Ruby 1.8.
|
73
|
+
* Ruby 1.8.5 or better
|
74
74
|
|
75
75
|
==Authors
|
76
76
|
|
data/Rakefile
CHANGED
@@ -3,14 +3,14 @@ require 'rake'
|
|
3
3
|
require 'echoe'
|
4
4
|
require 'hanna/rdoctask'
|
5
5
|
|
6
|
-
Echoe.new('ucb_ldap', '1.
|
6
|
+
Echoe.new('ucb_ldap', '1.4.2') do |p|
|
7
7
|
p.description = "Convenience classes for interacing with UCB's LDAP directory"
|
8
8
|
p.url = "http://ucbrb.rubyforge.org/ucb_ldap"
|
9
9
|
p.author = "Steven Hansen, Steve Downey, Lucas Rockwell"
|
10
10
|
p.email = "runner@berkeley.edu"
|
11
11
|
p.ignore_pattern = ["svn_user.yml", "tasks/ucb_ldap.rake", "spec/**/**", "test/**/**"]
|
12
12
|
p.project = "ucbrb"
|
13
|
-
p.runtime_dependencies = ["ruby-net-ldap >=
|
13
|
+
p.runtime_dependencies = ["ruby-net-ldap >=0.0.4"]
|
14
14
|
p.rdoc_options = "-o doc --inline-source -T hanna lib/*.rb"
|
15
15
|
p.rdoc_pattern = ["README", "lib/**/**"]
|
16
16
|
end
|
data/TODO
CHANGED
@@ -1,2 +1,2 @@
|
|
1
|
-
|
1
|
+
* Make thread safe, mutex around search?
|
2
2
|
|
@@ -2,25 +2,31 @@
|
|
2
2
|
|
3
3
|
module UCB::LDAP
|
4
4
|
module AffiliationMethods
|
5
|
-
|
6
|
-
|
5
|
+
|
6
|
+
##
|
7
|
+
# Returns an <tt>Array</tt> of Person's affiliations.
|
8
|
+
#
|
7
9
|
def affiliations
|
8
10
|
@affiliations ||= berkeleyEduAffiliations.map { |a| a.upcase }
|
9
11
|
end
|
10
|
-
|
12
|
+
|
13
|
+
##
|
11
14
|
# Returns <tt>true</tt> if entry's affiliations contain _affiliation_.
|
12
15
|
#
|
13
16
|
# Case-insensitive.
|
17
|
+
#
|
14
18
|
def has_affiliation?(affiliation)
|
15
19
|
affiliations.include?(affiliation.upcase)
|
16
20
|
end
|
17
|
-
|
21
|
+
|
22
|
+
##
|
18
23
|
# Returns <tt>true</tt> if Person's affiliations contain at least one affiliation of a particular type.
|
19
24
|
#
|
20
25
|
# p = Person.find_by_uid ...
|
21
26
|
# p.affiliations #=> ['EMPLOYEE-TYPE-STAFF']
|
22
27
|
# p.has_affiliation_of_type?(:employee) #=> true
|
23
28
|
# p.has_affiliation_of_type?(:student) #=> false
|
29
|
+
#
|
24
30
|
def has_affiliation_of_type?(affiliation_type)
|
25
31
|
aff_type_string = affiliation_type.to_s.upcase
|
26
32
|
affiliations.find{|a| a =~ /^#{aff_type_string}-TYPE-/} ? true : false
|
@@ -30,8 +36,10 @@ module UCB::LDAP
|
|
30
36
|
############################################
|
31
37
|
# Determine if the person is an EMPLOYEE #
|
32
38
|
############################################
|
33
|
-
|
39
|
+
|
40
|
+
##
|
34
41
|
# Returns <tt>true</tt> if entry has the "staff" affiliation.
|
42
|
+
#
|
35
43
|
def employee_staff?
|
36
44
|
has_affiliation? 'EMPLOYEE-TYPE-STAFF'
|
37
45
|
end
|
@@ -56,8 +64,10 @@ module UCB::LDAP
|
|
56
64
|
##########################################
|
57
65
|
# Determine if the person is a STUDENT #
|
58
66
|
##########################################
|
59
|
-
|
67
|
+
|
68
|
+
##
|
60
69
|
# Returns +true+ if is an expired student.
|
70
|
+
#
|
61
71
|
def student_expired?
|
62
72
|
has_affiliation? 'STUDENT-STATUS-EXPIRED'
|
63
73
|
end
|
@@ -73,9 +83,11 @@ module UCB::LDAP
|
|
73
83
|
def student_not_registered?
|
74
84
|
has_affiliation? 'STUDENT-TYPE-NOT REGISTERED'
|
75
85
|
end
|
76
|
-
|
86
|
+
|
87
|
+
##
|
77
88
|
# Returns <tt>true</tt> if entry has a studend affiliation and
|
78
89
|
# is not expired.
|
90
|
+
#
|
79
91
|
def student?
|
80
92
|
has_affiliation_of_type?(:student) && !student_expired?
|
81
93
|
end
|
@@ -100,9 +112,11 @@ module UCB::LDAP
|
|
100
112
|
def affiliate_directory_only?
|
101
113
|
has_affiliation? 'AFFILIATE-TYPE-DIRECTORY ONLY'
|
102
114
|
end
|
103
|
-
|
115
|
+
|
116
|
+
##
|
104
117
|
# Note: there are actually 2 types of visting affiliaties, visiting student and
|
105
118
|
# visiting scholars. But for now we will generalize.
|
119
|
+
#
|
106
120
|
def affiliate_visiting?
|
107
121
|
has_affiliation? 'AFFILIATE-TYPE-VISITING'
|
108
122
|
end
|
@@ -209,4 +223,3 @@ module UCB::LDAP
|
|
209
223
|
|
210
224
|
end
|
211
225
|
end
|
212
|
-
|
data/lib/ucb_ldap.rb
CHANGED
@@ -1,4 +1,3 @@
|
|
1
|
-
#
|
2
1
|
require 'rubygems'
|
3
2
|
require 'net/ldap'
|
4
3
|
require 'time'
|
@@ -19,8 +18,8 @@ require 'ucb_ldap_student_term'
|
|
19
18
|
require 'ucb_ldap_affiliation'
|
20
19
|
require 'ucb_ldap_service'
|
21
20
|
|
22
|
-
|
23
21
|
module UCB #:nodoc:
|
22
|
+
##
|
24
23
|
# =UCB::LDAP
|
25
24
|
#
|
26
25
|
# <b>If you are doing searches that don't require a privileged bind
|
@@ -37,29 +36,34 @@ module UCB #:nodoc:
|
|
37
36
|
|
38
37
|
HOST_PRODUCTION = 'ldap.berkeley.edu'
|
39
38
|
HOST_TEST = 'ldap-test.berkeley.edu'
|
40
|
-
|
41
|
-
# class methods
|
39
|
+
|
42
40
|
class << self
|
43
|
-
|
41
|
+
##
|
44
42
|
# Give (new) bind credentials to LDAP. An attempt will be made
|
45
43
|
# to bind and will raise BindFailedException if bind fails.
|
46
44
|
#
|
47
45
|
# Call clear_authentication() to remove privileged bind.
|
46
|
+
#
|
48
47
|
def authenticate(username, password)
|
49
48
|
@username, @password = username, password
|
50
|
-
new_net_ldap # to force bind()
|
49
|
+
new_net_ldap() # to force bind()
|
51
50
|
end
|
52
|
-
|
51
|
+
|
52
|
+
##
|
53
53
|
# Removes current bind (username, password).
|
54
|
-
|
54
|
+
#
|
55
|
+
def clear_authentication()
|
55
56
|
authenticate(nil, nil)
|
56
57
|
end
|
57
|
-
|
58
|
+
|
59
|
+
##
|
58
60
|
# Returns LDAP host used for lookups. Default is HOST_PRODUCTION.
|
59
|
-
|
61
|
+
#
|
62
|
+
def host()
|
60
63
|
@host || HOST_PRODUCTION
|
61
64
|
end
|
62
|
-
|
65
|
+
|
66
|
+
##
|
63
67
|
# Setter for #host.
|
64
68
|
#
|
65
69
|
# Note: validation of host is deferred until a search is performed
|
@@ -67,13 +71,15 @@ module UCB #:nodoc:
|
|
67
71
|
# raise ConnectionFailedException.
|
68
72
|
#---
|
69
73
|
# Don't want to reconnect unless host really changed.
|
74
|
+
#
|
70
75
|
def host=(host)
|
71
76
|
if host != @host
|
72
77
|
@host = host
|
73
78
|
@net_ldap = nil
|
74
79
|
end
|
75
80
|
end
|
76
|
-
|
81
|
+
|
82
|
+
##
|
77
83
|
# Returns Net::LDAP instance that is used by UCB::LDAP::Entry
|
78
84
|
# and subclasses for directory searches.
|
79
85
|
#
|
@@ -81,19 +87,21 @@ module UCB #:nodoc:
|
|
81
87
|
# sub-classes of Entry.
|
82
88
|
#
|
83
89
|
# Note: callers should not cache the results of this call unless they
|
84
|
-
# are prepared to handle timed-out connections (which this method does).
|
85
|
-
|
86
|
-
|
90
|
+
# are prepared to handle timed-out connections (which this method does).
|
91
|
+
#
|
92
|
+
def net_ldap()
|
93
|
+
@net_ldap ||= new_net_ldap
|
87
94
|
end
|
88
95
|
|
89
|
-
def password #:nodoc:
|
96
|
+
def password() #:nodoc:
|
90
97
|
@password
|
91
98
|
end
|
92
99
|
|
93
|
-
def username #:nodoc:
|
100
|
+
def username() #:nodoc:
|
94
101
|
@username
|
95
102
|
end
|
96
|
-
|
103
|
+
|
104
|
+
##
|
97
105
|
# If you are using UCB::LDAP in a Rails application you can specify binds on a
|
98
106
|
# per-environment basis, just as you can with database credentials.
|
99
107
|
#
|
@@ -113,6 +121,7 @@ module UCB #:nodoc:
|
|
113
121
|
#
|
114
122
|
# Runtime error will be raised if bind_file not found or if environment key not
|
115
123
|
# found in bind_file.
|
124
|
+
#
|
116
125
|
def bind_for_rails(bind_file = "#{RAILS_ROOT}/config/ldap.yml", environment = RAILS_ENV)
|
117
126
|
bind(bind_file, environment)
|
118
127
|
end
|
@@ -123,85 +132,73 @@ module UCB #:nodoc:
|
|
123
132
|
bind = binds[environment] || raise("Can't find environment=#{environment} in bind file")
|
124
133
|
authenticate(bind['username'], bind['password'])
|
125
134
|
end
|
126
|
-
|
135
|
+
|
136
|
+
##
|
127
137
|
# Returns +arg+ as a Ruby +Date+ in local time zone. Returns +nil+ if +arg+ is +nil+.
|
138
|
+
#
|
128
139
|
def local_date_parse(arg)
|
129
140
|
arg.nil? ? nil : Date.parse(Time.parse(arg.to_s).localtime.to_s)
|
130
141
|
end
|
131
|
-
|
142
|
+
|
143
|
+
##
|
132
144
|
# Returns +arg+ as a Ruby +DateTime+ in local time zone. Returns +nil+ if +arg+ is +nil+.
|
145
|
+
#
|
133
146
|
def local_datetime_parse(arg)
|
134
147
|
arg.nil? ? nil : DateTime.parse(Time.parse(arg.to_s).localtime.to_s)
|
135
148
|
end
|
136
149
|
|
137
150
|
private unless $TESTING
|
138
|
-
|
151
|
+
|
152
|
+
##
|
139
153
|
# The value of the :auth parameter for Net::LDAP.new().
|
140
|
-
|
154
|
+
#
|
155
|
+
def authentication_information()
|
141
156
|
password.nil? ?
|
142
157
|
{:method => :anonymous} :
|
143
158
|
{:method => :simple, :username => username, :password => password}
|
144
159
|
end
|
145
|
-
|
146
|
-
|
147
|
-
# connection.
|
148
|
-
def connection_open?
|
149
|
-
@net_ldap.nil? ? false : ldap_ping
|
150
|
-
rescue
|
151
|
-
false
|
152
|
-
end
|
153
|
-
|
160
|
+
|
161
|
+
##
|
154
162
|
# Returns +true+ if connection simple search works.
|
155
|
-
|
163
|
+
#
|
164
|
+
def ldap_ping()
|
156
165
|
search_attrs = {
|
157
166
|
:base => "",
|
158
167
|
:scope => Net::LDAP::SearchScope_BaseObject,
|
159
168
|
:attributes => [1.1]
|
160
169
|
}
|
161
170
|
result = false
|
162
|
-
@net_ldap.search(search_attrs){result = true}
|
171
|
+
@net_ldap.search(search_attrs) { result = true }
|
163
172
|
result
|
164
173
|
end
|
165
|
-
|
166
|
-
|
167
|
-
#
|
168
|
-
# variable.
|
174
|
+
|
175
|
+
##
|
176
|
+
# Returns new Net::LDAP instance.
|
169
177
|
#
|
170
|
-
# Warning: this seems to be contrary to the Net::LDAP author's
|
171
|
-
# intent and may break with future versions of Net::LDAP.
|
172
178
|
def new_net_ldap()
|
173
|
-
|
179
|
+
params = {
|
174
180
|
:host => host,
|
175
181
|
:auth => authentication_information,
|
176
182
|
:port => 636,
|
177
183
|
:encryption => {:method =>:simple_tls}
|
178
|
-
|
179
|
-
@net_ldap.
|
184
|
+
}
|
185
|
+
@net_ldap = Net::LDAP.new(params)
|
180
186
|
@net_ldap.bind || raise(BindFailedException)
|
181
187
|
@net_ldap
|
188
|
+
rescue Net::LDAP::LdapError => e
|
189
|
+
raise(BindFailedException)
|
182
190
|
end
|
183
|
-
|
184
|
-
|
185
|
-
def new_net_ldap_connection
|
186
|
-
Net::LDAP::Connection.new(
|
187
|
-
:host => host,
|
188
|
-
:port => 636,
|
189
|
-
:encryption => {:method => :simple_tls}
|
190
|
-
)
|
191
|
-
rescue Net::LDAP::LdapError
|
192
|
-
raise UCB::LDAP::ConnectionFailedException
|
193
|
-
end
|
194
|
-
|
191
|
+
|
192
|
+
##
|
195
193
|
# Used for testing
|
196
|
-
|
194
|
+
#
|
195
|
+
def clear_instance_variables()
|
197
196
|
@host = nil
|
198
197
|
@net_ldap = nil
|
199
198
|
@username = nil
|
200
199
|
@password = nil
|
201
200
|
end
|
202
|
-
|
203
201
|
end
|
204
|
-
|
205
|
-
end
|
202
|
+
end
|
206
203
|
end
|
207
204
|
|
data/lib/ucb_ldap_entry.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
module UCB
|
2
2
|
module LDAP
|
3
|
+
##
|
3
4
|
# = UCB::LDAP::Entry
|
4
5
|
#
|
5
6
|
# Abstract class representing an entry in the UCB LDAP directory. You
|
@@ -75,12 +76,14 @@ module UCB
|
|
75
76
|
# * #delete/#delete! - instance methods that do LDAP delete
|
76
77
|
#
|
77
78
|
class Entry
|
78
|
-
|
79
|
+
|
80
|
+
##
|
79
81
|
# Returns new instance of UCB::LDAP::Entry. The argument
|
80
82
|
# net_ldap_entry is an instance of Net::LDAP::Entry.
|
81
83
|
#
|
82
84
|
# You should not need to create any UCB::LDAP::Entry instances;
|
83
85
|
# they are created by calls to UCB::LDAP.search and friends.
|
86
|
+
#
|
84
87
|
def initialize(net_ldap_entry) #:nodoc:
|
85
88
|
# Don't store Net::LDAP entry in object since it uses the block
|
86
89
|
# initialization method of Hash which can't be marshalled ... this
|
@@ -90,7 +93,8 @@ module UCB
|
|
90
93
|
@attributes[canonical(attr)] = value.map{|v| v.dup}
|
91
94
|
end
|
92
95
|
end
|
93
|
-
|
96
|
+
|
97
|
+
##
|
94
98
|
# <tt>Hash</tt> of attributes returned from underlying NET::LDAP::Entry
|
95
99
|
# instance. Hash keys are #canonical attribute names, hash values are attribute
|
96
100
|
# values <em>as returned from LDAP</em>, i.e. arrays.
|
@@ -98,11 +102,14 @@ module UCB
|
|
98
102
|
# You should most likely be referencing attributes as if they were
|
99
103
|
# instance methods rather than directly through this method. See top of
|
100
104
|
# this document.
|
105
|
+
#
|
101
106
|
def attributes
|
102
107
|
@attributes
|
103
108
|
end
|
104
|
-
|
109
|
+
|
110
|
+
##
|
105
111
|
# Returns the value of the <em>Distinguished Name</em> attribute.
|
112
|
+
#
|
106
113
|
def dn
|
107
114
|
attributes[canonical(:dn)]
|
108
115
|
end
|
@@ -110,7 +117,8 @@ module UCB
|
|
110
117
|
def canonical(string_or_symbol) #:nodoc:
|
111
118
|
self.class.canonical(string_or_symbol)
|
112
119
|
end
|
113
|
-
|
120
|
+
|
121
|
+
##
|
114
122
|
# Update an existing entry. Returns entry if successful else false.
|
115
123
|
#
|
116
124
|
# attrs = {:attr1 => "new_v1", :attr2 => "new_v2"}
|
@@ -124,18 +132,24 @@ module UCB
|
|
124
132
|
end
|
125
133
|
false
|
126
134
|
end
|
127
|
-
|
128
|
-
|
135
|
+
|
136
|
+
##
|
137
|
+
# Same as #update_attributes(), but raises DirectoryNotUpdated on failure.
|
138
|
+
#
|
129
139
|
def update_attributes!(attrs)
|
130
140
|
update_attributes(attrs) || raise(DirectoryNotUpdatedException)
|
131
141
|
end
|
132
|
-
|
142
|
+
|
143
|
+
##
|
133
144
|
# Delete entry. Returns +true+ on sucess, +false+ on failure.
|
145
|
+
#
|
134
146
|
def delete
|
135
147
|
net_ldap.delete(:dn => dn)
|
136
148
|
end
|
137
|
-
|
149
|
+
|
150
|
+
##
|
138
151
|
# Same as #delete() except raises DirectoryNotUpdated on failure.
|
152
|
+
#
|
139
153
|
def delete!
|
140
154
|
delete || raise(DirectoryNotUpdatedException)
|
141
155
|
end
|
@@ -146,30 +160,38 @@ module UCB
|
|
146
160
|
|
147
161
|
|
148
162
|
private unless $TESTING
|
149
|
-
|
163
|
+
|
164
|
+
##
|
150
165
|
# Used to get/set attribute values.
|
151
166
|
#
|
152
167
|
# If we can't make an attribute name out of method, let
|
153
168
|
# regular method_missing() handle it.
|
169
|
+
#
|
154
170
|
def method_missing(method, *args) #:nodoc:
|
155
171
|
setter_method?(method) ? value_setter(method, *args) : value_getter(method)
|
156
172
|
rescue BadAttributeNameException
|
157
173
|
return super
|
158
174
|
end
|
159
|
-
|
175
|
+
|
176
|
+
##
|
160
177
|
# Returns +true+ if _method_ is a "setter", i.e., ends in "=".
|
178
|
+
#
|
161
179
|
def setter_method?(method)
|
162
180
|
method.to_s[-1, 1] == "="
|
163
181
|
end
|
164
|
-
|
165
|
-
|
182
|
+
|
183
|
+
##
|
184
|
+
# Called by method_missing() to get an attribute value.
|
185
|
+
#
|
166
186
|
def value_getter(method)
|
167
187
|
schema_attribute = self.class.schema_attribute(method)
|
168
188
|
raw_value = attributes[canonical(schema_attribute.name)]
|
169
189
|
schema_attribute.get_value(raw_value)
|
170
190
|
end
|
171
|
-
|
172
|
-
|
191
|
+
|
192
|
+
##
|
193
|
+
# Called by method_missing() to set an attribute value.
|
194
|
+
#
|
173
195
|
def value_setter(method, *args)
|
174
196
|
schema_attribute = self.class.schema_attribute(method.to_s.chop)
|
175
197
|
attr_key = canonical(schema_attribute.name)
|
@@ -220,10 +242,12 @@ module UCB
|
|
220
242
|
#
|
221
243
|
def create(args)
|
222
244
|
args[:attributes][:objectclass] = object_classes
|
223
|
-
net_ldap.add(args)
|
245
|
+
result = net_ldap.add(args)
|
246
|
+
result or return false
|
224
247
|
find_by_dn(args[:dn])
|
225
248
|
end
|
226
|
-
|
249
|
+
|
250
|
+
##
|
227
251
|
# Returns entry whose distinguised name is _dn_.
|
228
252
|
def find_by_dn(dn)
|
229
253
|
search(
|
@@ -232,12 +256,14 @@ module UCB
|
|
232
256
|
:filter => "objectClass=*"
|
233
257
|
).first
|
234
258
|
end
|
235
|
-
|
259
|
+
|
260
|
+
##
|
236
261
|
# Same as #create(), but raises DirectoryNotUpdated on failure.
|
237
262
|
def create!(args)
|
238
263
|
create(args) || raise(DirectoryNotUpdatedException)
|
239
264
|
end
|
240
|
-
|
265
|
+
|
266
|
+
##
|
241
267
|
# Returns a new Net::LDAP::Filter that is the result of combining
|
242
268
|
# <em>filters</em> using <em>operator</em> (<em>filters</em> is
|
243
269
|
# an +Array+ of Net::LDAP::Filter).
|
@@ -253,7 +279,8 @@ module UCB
|
|
253
279
|
def combine_filters(filters, operator = '&')
|
254
280
|
filters.inject{|accum, filter| accum.send(operator, filter)}
|
255
281
|
end
|
256
|
-
|
282
|
+
|
283
|
+
##
|
257
284
|
# Returns Net::LDAP::Filter. Allows for <em>filter</em> to
|
258
285
|
# be a +Hash+ of :key => value. Filters are combined with "&".
|
259
286
|
#
|
@@ -271,7 +298,8 @@ module UCB
|
|
271
298
|
end
|
272
299
|
combine_filters(filters, "&")
|
273
300
|
end
|
274
|
-
|
301
|
+
|
302
|
+
##
|
275
303
|
# Returns +Array+ of object classes making up this type of LDAP entity.
|
276
304
|
def object_classes
|
277
305
|
@object_classes ||= UCB::LDAP::Schema.schema_hash[entity_name]["objectClasses"]
|
@@ -281,14 +309,45 @@ module UCB
|
|
281
309
|
@unique_object_class ||= UCB::LDAP::Schema.schema_hash[entity_name]["uniqueObjectClass"]
|
282
310
|
end
|
283
311
|
|
312
|
+
##
|
313
|
+
# returns an Array of symbols where each symbol is the name of
|
314
|
+
# a required attribute for the Entry
|
315
|
+
def required_attributes
|
316
|
+
required_schema_attributes.keys
|
317
|
+
end
|
318
|
+
|
319
|
+
##
|
320
|
+
# returns Hash of SchemaAttribute objects that are required
|
321
|
+
# for the Entry. Each SchemaAttribute object is keyed to the
|
322
|
+
# attribute's name.
|
323
|
+
#
|
324
|
+
# Note: required_schema_attributes will not return aliases, it
|
325
|
+
# only returns the original attributes
|
326
|
+
#
|
327
|
+
# Example:
|
328
|
+
# Person.required_schema_attribues[:cn]
|
329
|
+
# => <UCB::LDAP::Schema::Attribute:0x11c6b68>
|
330
|
+
#
|
331
|
+
def required_schema_attributes
|
332
|
+
required_atts = schema_attributes_hash.reject { |key, value| !value.required? }
|
333
|
+
required_atts.reject do |key, value|
|
334
|
+
aliases = value.aliases.map { |a| canonical(a) }
|
335
|
+
aliases.include?(key)
|
336
|
+
end
|
337
|
+
end
|
338
|
+
|
339
|
+
##
|
284
340
|
# Returns an +Array+ of Schema::Attribute for the entity.
|
341
|
+
#
|
285
342
|
def schema_attributes_array
|
286
343
|
@schema_attributes_array || set_schema_attributes
|
287
344
|
@schema_attributes_array
|
288
345
|
end
|
289
|
-
|
346
|
+
|
347
|
+
##
|
290
348
|
# Returns as +Hash+ whose keys are the canonical attribute names
|
291
349
|
# and whose values are the corresponding Schema::Attributes.
|
350
|
+
#
|
292
351
|
def schema_attributes_hash
|
293
352
|
@schema_attributes_hash || set_schema_attributes
|
294
353
|
@schema_attributes_hash
|
@@ -298,7 +357,8 @@ module UCB
|
|
298
357
|
schema_attributes_hash[canonical(attribute_name)] ||
|
299
358
|
raise(BadAttributeNameException, "'#{attribute_name}' is not a recognized attribute name")
|
300
359
|
end
|
301
|
-
|
360
|
+
|
361
|
+
##
|
302
362
|
# Returns Array of UCB::LDAP::Entry for entries matching _args_.
|
303
363
|
# When called from a subclass, returns Array of subclass instances.
|
304
364
|
#
|
@@ -325,27 +385,35 @@ module UCB
|
|
325
385
|
end
|
326
386
|
results
|
327
387
|
end
|
328
|
-
|
388
|
+
|
389
|
+
##
|
329
390
|
# Returns the canonical representation of a symbol or string so
|
330
391
|
# we can look up attributes in a number of ways.
|
392
|
+
#
|
331
393
|
def canonical(string_or_symbol)
|
332
394
|
string_or_symbol.to_s.downcase.to_sym
|
333
395
|
end
|
334
|
-
|
396
|
+
|
397
|
+
##
|
335
398
|
# Returns underlying Net::LDAP instance.
|
399
|
+
#
|
336
400
|
def net_ldap #:nodoc:
|
337
401
|
UCB::LDAP.net_ldap
|
338
402
|
end
|
339
403
|
|
340
404
|
private unless $TESTING
|
341
|
-
|
405
|
+
|
406
|
+
##
|
342
407
|
# Schema entity name. Set in each subclass.
|
408
|
+
#
|
343
409
|
def entity_name
|
344
410
|
@entity_name
|
345
411
|
end
|
346
|
-
|
412
|
+
|
413
|
+
##
|
347
414
|
# Want an array of Schema::Attributes as well as a hash
|
348
415
|
# of all possible variations on a name pointing to correct array element.
|
416
|
+
#
|
349
417
|
def set_schema_attributes
|
350
418
|
@schema_attributes_array = []
|
351
419
|
@schema_attributes_hash = {}
|
@@ -360,10 +428,12 @@ module UCB
|
|
360
428
|
raise "Error loading schema attributes for entity_name '#{entity_name}'"
|
361
429
|
end
|
362
430
|
|
431
|
+
##
|
363
432
|
# Returns tree base for LDAP searches. Subclasses each have
|
364
433
|
# their own value.
|
365
434
|
#
|
366
435
|
# Can be overridden in #search by passing in a <tt>:base</tt> parm.
|
436
|
+
##
|
367
437
|
def tree_base
|
368
438
|
@tree_base
|
369
439
|
end
|