ucb_ldap 1.3.2 → 1.4.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.
- 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
|