activeldap 4.0.5 → 6.1.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 +5 -5
- data/.yardopts +3 -1
- data/doc/text/development.md +26 -0
- data/doc/text/{news.textile → news.md} +451 -241
- data/doc/text/{rails.textile → rails.md} +44 -33
- data/doc/text/{tutorial.textile → tutorial.md} +177 -185
- data/lib/active_ldap/adapter/base.rb +40 -17
- data/lib/active_ldap/adapter/jndi.rb +21 -9
- data/lib/active_ldap/adapter/jndi_connection.rb +83 -20
- data/lib/active_ldap/adapter/ldap.rb +50 -28
- data/lib/active_ldap/adapter/ldap_ext.rb +32 -13
- data/lib/active_ldap/adapter/net_ldap.rb +26 -24
- data/lib/active_ldap/associations.rb +5 -5
- data/lib/active_ldap/attribute_methods/before_type_cast.rb +1 -1
- data/lib/active_ldap/attribute_methods/dirty.rb +4 -7
- data/lib/active_ldap/attribute_methods/query.rb +1 -1
- data/lib/active_ldap/attribute_methods/read.rb +5 -1
- data/lib/active_ldap/attribute_methods/write.rb +1 -1
- data/lib/active_ldap/attribute_methods.rb +1 -2
- data/lib/active_ldap/base.rb +61 -14
- data/lib/active_ldap/callbacks.rb +7 -8
- data/lib/active_ldap/configuration.rb +27 -3
- data/lib/active_ldap/connection.rb +4 -22
- data/lib/active_ldap/distinguished_name.rb +1 -1
- data/lib/active_ldap/human_readable.rb +5 -4
- data/lib/active_ldap/operations.rb +24 -4
- data/lib/active_ldap/persistence.rb +3 -2
- data/lib/active_ldap/populate.rb +5 -3
- data/lib/active_ldap/railties/controller_runtime.rb +1 -2
- data/lib/active_ldap/schema/syntaxes.rb +8 -4
- data/lib/active_ldap/validations.rb +12 -4
- data/lib/active_ldap/version.rb +1 -1
- data/lib/active_ldap.rb +0 -7
- data/po/en/active-ldap.po +2 -2
- data/po/ja/active-ldap.po +3 -3
- data/test/add-phonetic-attribute-options-to-slapd.ldif +3 -3
- data/test/al-test-utils.rb +125 -38
- data/test/command.rb +13 -16
- data/test/enable-dynamic-groups.ldif +22 -0
- data/test/enable-start-tls.ldif +27 -0
- data/test/run-test.rb +0 -4
- data/test/test_base.rb +223 -22
- data/test/test_base_per_instance.rb +33 -1
- data/test/test_callback.rb +10 -8
- data/test/test_connection.rb +4 -0
- data/test/test_connection_per_class.rb +34 -0
- data/test/test_dn.rb +7 -0
- data/test/test_entry.rb +1 -0
- data/test/test_find.rb +14 -3
- data/test/test_supported_control.rb +1 -1
- data/test/test_syntax.rb +5 -0
- data/test/test_validation.rb +28 -15
- metadata +23 -24
- data/README.textile +0 -141
- data/doc/text/development.textile +0 -54
- data/lib/active_ldap/timeout.rb +0 -75
- data/lib/active_ldap/timeout_stub.rb +0 -17
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'timeout'
|
2
|
+
|
1
3
|
require 'active_ldap/schema'
|
2
4
|
require 'active_ldap/entry_attribute'
|
3
5
|
require 'active_ldap/ldap_error'
|
@@ -12,6 +14,7 @@ module ActiveLdap
|
|
12
14
|
:host,
|
13
15
|
:port,
|
14
16
|
:method,
|
17
|
+
:tls_options,
|
15
18
|
:timeout,
|
16
19
|
:retry_on_timeout,
|
17
20
|
:retry_limit,
|
@@ -27,6 +30,8 @@ module ActiveLdap
|
|
27
30
|
:scope,
|
28
31
|
:sasl_options,
|
29
32
|
:follow_referrals,
|
33
|
+
:use_paged_results,
|
34
|
+
:page_size,
|
30
35
|
]
|
31
36
|
|
32
37
|
@@row_even = true
|
@@ -38,6 +43,7 @@ module ActiveLdap
|
|
38
43
|
@bind_tried = false
|
39
44
|
@entry_attributes = {}
|
40
45
|
@follow_referrals = nil
|
46
|
+
@page_size = nil
|
41
47
|
@configuration = configuration.dup
|
42
48
|
@logger = @configuration.delete(:logger)
|
43
49
|
@configuration.assert_valid_keys(VALID_ADAPTER_CONFIGURATION_KEYS)
|
@@ -45,6 +51,7 @@ module ActiveLdap
|
|
45
51
|
instance_variable_set("@#{name}", configuration[name])
|
46
52
|
end
|
47
53
|
@follow_referrals = true if @follow_referrals.nil?
|
54
|
+
@page_size ||= Configuration::DEFAULT_CONFIG[:page_size]
|
48
55
|
@instrumenter = ActiveSupport::Notifications.instrumenter
|
49
56
|
end
|
50
57
|
|
@@ -166,23 +173,40 @@ module ActiveLdap
|
|
166
173
|
end
|
167
174
|
|
168
175
|
def search(options={})
|
169
|
-
filter = parse_filter(options[:filter]) || 'objectClass=*'
|
170
|
-
attrs = options[:attributes] || []
|
171
|
-
scope = ensure_scope(options[:scope] || @scope)
|
172
176
|
base = options[:base]
|
177
|
+
base = ensure_dn_string(base)
|
178
|
+
attributes = options[:attributes] || []
|
179
|
+
attributes = attributes.to_a # just in case
|
173
180
|
limit = options[:limit] || 0
|
174
181
|
limit = nil if limit <= 0
|
182
|
+
use_paged_results = options[:use_paged_results]
|
183
|
+
use_paged_results = @use_paged_results if use_paged_results.nil?
|
184
|
+
if use_paged_results
|
185
|
+
use_paged_results = limit != 1 && supported_control.paged_results?
|
186
|
+
end
|
187
|
+
search_options = {
|
188
|
+
base: base,
|
189
|
+
scope: ensure_scope(options[:scope] || @scope),
|
190
|
+
filter: parse_filter(options[:filter]) || 'objectClass=*',
|
191
|
+
attributes: attributes,
|
192
|
+
limit: limit,
|
193
|
+
use_paged_results: use_paged_results,
|
194
|
+
page_size: options[:page_size] || @page_size,
|
195
|
+
}
|
175
196
|
|
176
|
-
attrs = attrs.to_a # just in case
|
177
|
-
base = ensure_dn_string(base)
|
178
197
|
begin
|
179
198
|
operation(options) do
|
180
|
-
yield(
|
199
|
+
yield(search_options)
|
181
200
|
end
|
182
|
-
rescue LdapError::NoSuchObject, LdapError::InvalidDnSyntax
|
201
|
+
rescue LdapError::NoSuchObject, LdapError::InvalidDnSyntax => error
|
183
202
|
# Do nothing on failure
|
184
203
|
@logger.info do
|
185
|
-
args = [
|
204
|
+
args = [
|
205
|
+
error.class.class,
|
206
|
+
error.message,
|
207
|
+
search_options[:filter],
|
208
|
+
search_options[:attributes].inspect,
|
209
|
+
]
|
186
210
|
_("Ignore error %s(%s): filter %s: attributes: %s") % args
|
187
211
|
end
|
188
212
|
end
|
@@ -328,7 +352,7 @@ module ActiveLdap
|
|
328
352
|
n_retries = 0
|
329
353
|
retry_limit = options[:retry_limit] || @retry_limit
|
330
354
|
begin
|
331
|
-
|
355
|
+
Timeout.timeout(@timeout, &block)
|
332
356
|
rescue Timeout::Error => e
|
333
357
|
@logger.error {_('Requested action timed out.')}
|
334
358
|
if @retry_on_timeout and (retry_limit < 0 or n_retries <= retry_limit)
|
@@ -344,10 +368,6 @@ module ActiveLdap
|
|
344
368
|
end
|
345
369
|
end
|
346
370
|
|
347
|
-
def do_in_timeout(timeout, &block)
|
348
|
-
Timeout.alarm(timeout, &block)
|
349
|
-
end
|
350
|
-
|
351
371
|
def sasl_bind(bind_dn, options={})
|
352
372
|
# Get all SASL mechanisms
|
353
373
|
mechanisms = operation(options) do
|
@@ -601,9 +621,13 @@ module ActiveLdap
|
|
601
621
|
raise
|
602
622
|
rescue => detail
|
603
623
|
@logger.error do
|
604
|
-
_("Reconnect to server failed: %s\n" \
|
624
|
+
_("Reconnect to server failed: %s: %s\n" \
|
605
625
|
"Reconnect to server failed backtrace:\n" \
|
606
|
-
"%s") % [
|
626
|
+
"%s") % [
|
627
|
+
detail.class,
|
628
|
+
detail.message,
|
629
|
+
detail.backtrace.join("\n"),
|
630
|
+
]
|
607
631
|
end
|
608
632
|
# Do not loop if forced
|
609
633
|
raise ConnectionError, detail.message if force
|
@@ -659,8 +683,7 @@ module ActiveLdap
|
|
659
683
|
:scope => :base,
|
660
684
|
:attributes => attrs,
|
661
685
|
:limit => 1,
|
662
|
-
:try_reconnect => try_reconnect,
|
663
|
-
:use_paged_results => false) do |dn, attributes|
|
686
|
+
:try_reconnect => try_reconnect) do |dn, attributes|
|
664
687
|
found_attributes = attributes
|
665
688
|
end
|
666
689
|
found_attributes
|
@@ -22,9 +22,23 @@ module ActiveLdap
|
|
22
22
|
super do |host, port, method|
|
23
23
|
uri = construct_uri(host, port, method == :ssl)
|
24
24
|
with_start_tls = method == :start_tls
|
25
|
-
|
26
|
-
|
27
|
-
|
25
|
+
follow_referrals = follow_referrals?(options)
|
26
|
+
info = {
|
27
|
+
:uri => uri,
|
28
|
+
:with_start_tls => with_start_tls,
|
29
|
+
:follow_referrals => follow_referrals,
|
30
|
+
}
|
31
|
+
[
|
32
|
+
log("connect", info) {
|
33
|
+
JndiConnection.new(host,
|
34
|
+
port,
|
35
|
+
method,
|
36
|
+
@timeout,
|
37
|
+
follow_referrals)
|
38
|
+
},
|
39
|
+
uri,
|
40
|
+
with_start_tls,
|
41
|
+
]
|
28
42
|
end
|
29
43
|
end
|
30
44
|
|
@@ -46,12 +60,10 @@ module ActiveLdap
|
|
46
60
|
end
|
47
61
|
|
48
62
|
def search(options={}, &block)
|
49
|
-
super(options) do |
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
}
|
54
|
-
execute(:search, info, base, scope, filter, attrs, limit, &block)
|
63
|
+
super(options) do |search_options|
|
64
|
+
scope = search_options[:scope]
|
65
|
+
info = search_options.merge(scope: scope_name(scope))
|
66
|
+
execute(:search, info, search_options, &block)
|
55
67
|
end
|
56
68
|
end
|
57
69
|
|
@@ -25,6 +25,8 @@ module ActiveLdap
|
|
25
25
|
Context = naming.Context
|
26
26
|
StartTlsRequest = ldap.StartTlsRequest
|
27
27
|
Control = ldap.Control
|
28
|
+
PagedResultsControl = ldap.PagedResultsControl
|
29
|
+
PagedResultsResponseControl = ldap.PagedResultsResponseControl
|
28
30
|
|
29
31
|
CommunicationException = naming.CommunicationException
|
30
32
|
ServiceUnavailableException = naming.ServiceUnavailableException
|
@@ -73,13 +75,14 @@ module ActiveLdap
|
|
73
75
|
end
|
74
76
|
end
|
75
77
|
|
76
|
-
def initialize(host, port, method, timeout)
|
78
|
+
def initialize(host, port, method, timeout, follow_referrals)
|
77
79
|
@host = host
|
78
80
|
@port = port
|
79
81
|
@method = method
|
80
82
|
@timeout = timeout
|
81
83
|
@context = nil
|
82
84
|
@tls = nil
|
85
|
+
@follow_referrals = follow_referrals
|
83
86
|
end
|
84
87
|
|
85
88
|
def unbind
|
@@ -108,23 +111,55 @@ module ActiveLdap
|
|
108
111
|
bound?
|
109
112
|
end
|
110
113
|
|
111
|
-
def search(
|
114
|
+
def search(options)
|
115
|
+
base = options[:base]
|
116
|
+
scope = options[:scope]
|
117
|
+
filter = options[:filter]
|
118
|
+
attributes = options[:attributes]
|
119
|
+
limit = options[:limit]
|
120
|
+
use_paged_results = options[:use_paged_results]
|
121
|
+
page_size = options[:page_size]
|
122
|
+
|
112
123
|
controls = SearchControls.new
|
113
124
|
controls.search_scope = scope
|
114
125
|
|
115
126
|
controls.count_limit = limit if limit
|
116
|
-
unless
|
117
|
-
controls.returning_attributes =
|
127
|
+
unless attributes.blank?
|
128
|
+
controls.returning_attributes = attributes.to_java(:string)
|
129
|
+
end
|
130
|
+
|
131
|
+
page_cookie = nil
|
132
|
+
if use_paged_results
|
133
|
+
# https://devdocs.io/openjdk~8/javax/naming/ldap/pagedresultscontrol
|
134
|
+
@context.set_request_controls([build_paged_results_control(page_size)])
|
135
|
+
else
|
136
|
+
@context.set_request_controls([])
|
118
137
|
end
|
119
138
|
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
end
|
139
|
+
escaped_base = escape_dn(base)
|
140
|
+
|
141
|
+
loop do
|
142
|
+
@context.search(escaped_base, filter, controls).each do |search_result|
|
143
|
+
yield(build_raw_search_result(search_result))
|
126
144
|
end
|
127
|
-
|
145
|
+
|
146
|
+
break unless use_paged_results
|
147
|
+
|
148
|
+
# Find the paged search cookie
|
149
|
+
response_controls = @context.get_response_controls
|
150
|
+
break unless response_controls
|
151
|
+
response_controls.each do |response_control|
|
152
|
+
next unless response_control.is_a?(PagedResultsResponseControl)
|
153
|
+
page_cookie = response_control.get_cookie
|
154
|
+
break
|
155
|
+
end
|
156
|
+
|
157
|
+
break unless page_cookie
|
158
|
+
|
159
|
+
# Set paged results control so we can keep getting results.
|
160
|
+
paged_results_control =
|
161
|
+
build_paged_results_control(page_size, page_cookie)
|
162
|
+
@context.set_request_controls([paged_results_control])
|
128
163
|
end
|
129
164
|
end
|
130
165
|
|
@@ -133,25 +168,32 @@ module ActiveLdap
|
|
133
168
|
records.each do |record|
|
134
169
|
attributes.put(record.to_java_attribute)
|
135
170
|
end
|
136
|
-
@context.
|
171
|
+
@context.set_request_controls([])
|
172
|
+
@context.create_subcontext(escape_dn(dn), attributes)
|
137
173
|
end
|
138
174
|
|
139
175
|
def modify(dn, records)
|
140
176
|
items = records.collect(&:to_java_modification_item)
|
141
|
-
@context.
|
177
|
+
@context.set_request_controls([])
|
178
|
+
@context.modify_attributes(escape_dn(dn), items.to_java(ModificationItem))
|
142
179
|
end
|
143
180
|
|
144
181
|
def modify_rdn(dn, new_rdn, delete_old_rdn)
|
145
182
|
# should use mutex
|
146
183
|
delete_rdn_key = "java.naming.ldap.deleteRDN"
|
147
|
-
@context.
|
148
|
-
|
149
|
-
|
150
|
-
|
184
|
+
@context.set_request_controls([])
|
185
|
+
begin
|
186
|
+
@context.add_to_environment(delete_rdn_key, delete_old_rdn.to_s)
|
187
|
+
@context.rename(escape_dn(dn), escape_dn(new_rdn))
|
188
|
+
ensure
|
189
|
+
@context.remove_from_environment(delete_rdn_key)
|
190
|
+
end
|
151
191
|
end
|
152
192
|
|
153
193
|
def delete(dn)
|
154
|
-
|
194
|
+
escaped_dn = escape_dn(dn)
|
195
|
+
@context.set_request_controls([])
|
196
|
+
@context.destroy_subcontext(escaped_dn)
|
155
197
|
end
|
156
198
|
|
157
199
|
private
|
@@ -162,9 +204,10 @@ module ActiveLdap
|
|
162
204
|
Context::PROVIDER_URL => ldap_uri,
|
163
205
|
'com.sun.jndi.ldap.connect.timeout' => (@timeout * 1000).to_i.to_s,
|
164
206
|
'com.sun.jndi.ldap.read.timeout' => (@timeout * 1000).to_i.to_s,
|
207
|
+
'java.naming.ldap.derefAliases' => 'never',
|
208
|
+
'java.naming.referral' => @follow_referrals ? 'follow' : 'ignore',
|
165
209
|
}
|
166
|
-
|
167
|
-
context = InitialLdapContext.new(environment, nil)
|
210
|
+
context = InitialLdapContext.new(HashTable.new(environment), nil)
|
168
211
|
if @method == :start_tls
|
169
212
|
@tls = context.extended_operation(StartTlsRequest.new)
|
170
213
|
@tls.negotiate
|
@@ -185,6 +228,26 @@ module ActiveLdap
|
|
185
228
|
protocol = @method == :ssl ? "ldaps" : "ldap"
|
186
229
|
"#{protocol}://#{@host}:#{@port}/"
|
187
230
|
end
|
231
|
+
|
232
|
+
def escape_dn(dn)
|
233
|
+
javax.naming.ldap.LdapName.new(dn)
|
234
|
+
rescue Java::JavaLang::IllegalArgumentException, Java::JavaxNaming::InvalidNameException
|
235
|
+
dn
|
236
|
+
end
|
237
|
+
|
238
|
+
def build_paged_results_control(page_size, page_cookie=nil)
|
239
|
+
PagedResultsControl.new(page_size, page_cookie, Control::CRITICAL)
|
240
|
+
end
|
241
|
+
|
242
|
+
def build_raw_search_result(search_result)
|
243
|
+
attributes = {}
|
244
|
+
search_result.attributes.get_all.each do |attribute|
|
245
|
+
attributes[attribute.get_id] = attribute.get_all.collect do |value|
|
246
|
+
value.is_a?(String) ? value : String.from_java_bytes(value)
|
247
|
+
end
|
248
|
+
end
|
249
|
+
[search_result.name_in_namespace, attributes]
|
250
|
+
end
|
188
251
|
end
|
189
252
|
end
|
190
253
|
end
|
@@ -24,7 +24,7 @@ module ActiveLdap
|
|
24
24
|
end
|
25
25
|
|
26
26
|
class SSL < Base
|
27
|
-
def connect(host, port)
|
27
|
+
def connect(host, port, options={})
|
28
28
|
LDAP::SSLConn.new(host, port, false)
|
29
29
|
end
|
30
30
|
|
@@ -34,8 +34,35 @@ module ActiveLdap
|
|
34
34
|
end
|
35
35
|
|
36
36
|
class TLS < Base
|
37
|
-
def connect(host, port)
|
38
|
-
LDAP::
|
37
|
+
def connect(host, port, options={})
|
38
|
+
connection = LDAP::Conn.new(host, port)
|
39
|
+
if connection.get_option(LDAP::LDAP_OPT_PROTOCOL_VERSION) < 3
|
40
|
+
connection.set_option(LDAP::LDAP_OPT_PROTOCOL_VERSION, 3)
|
41
|
+
end
|
42
|
+
tls_options = options[:tls_options]
|
43
|
+
if tls_options and LDAP.const_defined?(:LDAP_OPT_X_TLS_NEWCTX)
|
44
|
+
tls_options.each do |key, value|
|
45
|
+
case key
|
46
|
+
when :verify_mode
|
47
|
+
case value
|
48
|
+
when :none, OpenSSL::SSL::SSL_VERIFY_NONE
|
49
|
+
connection.set_option(LDAP::LDAP_OPT_X_TLS_REQUIRE_CERT,
|
50
|
+
LDAP::LDAP_OPT_X_TLS_NEVER)
|
51
|
+
when :peer, OpenSSL::SSL::SSL_VERIFY_PEER
|
52
|
+
connection.set_option(LDAP::LDAP_OPT_X_TLS_REQUIRE_CERT,
|
53
|
+
LDAP::LDAP_OPT_X_TLS_DEMAND)
|
54
|
+
end
|
55
|
+
when :verify_hostname
|
56
|
+
unless value
|
57
|
+
connection.set_option(LDAP::LDAP_OPT_X_TLS_REQUIRE_CERT,
|
58
|
+
LDAP::LDAP_OPT_X_TLS_ALLOW)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
connection.set_option(LDAP::LDAP_OPT_X_TLS_NEWCTX, 0)
|
63
|
+
end
|
64
|
+
connection.start_tls
|
65
|
+
connection
|
39
66
|
end
|
40
67
|
|
41
68
|
def start_tls?
|
@@ -44,7 +71,7 @@ module ActiveLdap
|
|
44
71
|
end
|
45
72
|
|
46
73
|
class Plain < Base
|
47
|
-
def connect(host, port)
|
74
|
+
def connect(host, port, options={})
|
48
75
|
LDAP::Conn.new(host, port)
|
49
76
|
end
|
50
77
|
end
|
@@ -54,9 +81,13 @@ module ActiveLdap
|
|
54
81
|
super do |host, port, method|
|
55
82
|
uri = construct_uri(host, port, method.ssl?)
|
56
83
|
with_start_tls = method.start_tls?
|
57
|
-
info = {
|
84
|
+
info = {
|
85
|
+
:uri => uri,
|
86
|
+
:with_start_tls => with_start_tls,
|
87
|
+
:tls_options => @tls_options,
|
88
|
+
}
|
58
89
|
connection = log("connect", info) do
|
59
|
-
method.connect(host, port)
|
90
|
+
method.connect(host, port, :tls_options => @tls_options)
|
60
91
|
end
|
61
92
|
[connection, uri, with_start_tls]
|
62
93
|
end
|
@@ -82,25 +113,11 @@ module ActiveLdap
|
|
82
113
|
end
|
83
114
|
|
84
115
|
def search(options={})
|
85
|
-
super(options) do |
|
116
|
+
super(options) do |search_options|
|
86
117
|
begin
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
end
|
91
|
-
info = {
|
92
|
-
:base => base, :scope => scope_name(scope),
|
93
|
-
:filter => filter, :attributes => attrs, :limit => limit,
|
94
|
-
}
|
95
|
-
options = {
|
96
|
-
:base => base,
|
97
|
-
:scope => scope,
|
98
|
-
:filter => filter,
|
99
|
-
:attributes => attrs,
|
100
|
-
:limit => limit,
|
101
|
-
:use_paged_results => use_paged_results
|
102
|
-
}
|
103
|
-
execute(:search_full, info, options) do |entry|
|
118
|
+
scope = search_options[:scope]
|
119
|
+
info = search_options.merge(scope: scope_name(scope))
|
120
|
+
execute(:search_full, info, search_options) do |entry|
|
104
121
|
attributes = {}
|
105
122
|
entry.attrs.each do |attr|
|
106
123
|
value = entry.vals(attr)
|
@@ -111,7 +128,10 @@ module ActiveLdap
|
|
111
128
|
rescue RuntimeError
|
112
129
|
if $!.message == "no result returned by search"
|
113
130
|
@logger.debug do
|
114
|
-
args = [
|
131
|
+
args = [
|
132
|
+
search_options[:filter],
|
133
|
+
search_options[:attributes].inspect,
|
134
|
+
]
|
115
135
|
_("No matches: filter: %s: attributes: %s") % args
|
116
136
|
end
|
117
137
|
else
|
@@ -189,15 +209,17 @@ module ActiveLdap
|
|
189
209
|
def prepare_connection(options={})
|
190
210
|
operation(options) do
|
191
211
|
@connection.set_option(LDAP::LDAP_OPT_PROTOCOL_VERSION, 3)
|
192
|
-
|
193
|
-
|
194
|
-
|
212
|
+
@ldap_follow_referrals = follow_referrals?(options) ? 1 : 0
|
213
|
+
@connection.set_option(LDAP::LDAP_OPT_REFERRALS,
|
214
|
+
@ldap_follow_referrals)
|
195
215
|
end
|
196
216
|
end
|
197
217
|
|
198
218
|
def execute(method, info=nil, *args, &block)
|
199
219
|
begin
|
200
220
|
name = (info || {}).delete(:name) || method
|
221
|
+
@connection.set_option(LDAP::LDAP_OPT_REFERRALS,
|
222
|
+
@ldap_follow_referrals)
|
201
223
|
log(name, info) {@connection.send(method, *args, &block)}
|
202
224
|
rescue LDAP::ResultError
|
203
225
|
@connection.assert_error_code
|
@@ -65,12 +65,28 @@ module LDAP
|
|
65
65
|
attributes = options[:attributes]
|
66
66
|
limit = options[:limit] || 0
|
67
67
|
use_paged_results = options[:use_paged_results]
|
68
|
+
page_size = options[:page_size]
|
68
69
|
if @@have_search_ext
|
69
70
|
if use_paged_results
|
70
|
-
paged_search(base,
|
71
|
+
paged_search(base,
|
72
|
+
scope,
|
73
|
+
filter,
|
74
|
+
attributes,
|
75
|
+
limit,
|
76
|
+
page_size,
|
77
|
+
&block)
|
71
78
|
else
|
72
|
-
search_ext(base,
|
73
|
-
|
79
|
+
search_ext(base,
|
80
|
+
scope,
|
81
|
+
filter,
|
82
|
+
attributes,
|
83
|
+
false,
|
84
|
+
nil,
|
85
|
+
nil,
|
86
|
+
0,
|
87
|
+
0,
|
88
|
+
limit,
|
89
|
+
&block)
|
74
90
|
end
|
75
91
|
else
|
76
92
|
i = 0
|
@@ -120,27 +136,30 @@ module LDAP
|
|
120
136
|
end
|
121
137
|
end
|
122
138
|
|
123
|
-
def paged_search(base, scope, filter, attributes, limit, &block)
|
124
|
-
# work around a bug with openldap
|
125
|
-
page_size = 126
|
139
|
+
def paged_search(base, scope, filter, attributes, limit, page_size, &block)
|
126
140
|
cookie = ""
|
127
141
|
critical = true
|
128
|
-
|
129
142
|
loop do
|
130
143
|
ber_string = LDAP::Control.encode(page_size, cookie)
|
131
144
|
control = LDAP::Control.new(LDAP::LDAP_CONTROL_PAGEDRESULTS,
|
132
145
|
ber_string,
|
133
146
|
critical)
|
134
|
-
|
135
|
-
|
136
|
-
|
147
|
+
search_ext(base,
|
148
|
+
scope,
|
149
|
+
filter,
|
150
|
+
attributes,
|
151
|
+
false,
|
152
|
+
[control],
|
153
|
+
nil,
|
154
|
+
0,
|
155
|
+
0,
|
156
|
+
limit,
|
157
|
+
&block)
|
137
158
|
|
138
159
|
control = find_paged_results_control(@controls)
|
139
160
|
break if control.nil?
|
140
|
-
returned_size, cookie = control.decode
|
141
|
-
returned_size = returned_size.to_i
|
142
|
-
page_size = returned_size if returned_size > 0
|
143
161
|
|
162
|
+
_estimated_result_set_size, cookie = control.decode
|
144
163
|
break if cookie.empty?
|
145
164
|
end
|
146
165
|
end
|
@@ -26,15 +26,21 @@ module ActiveLdap
|
|
26
26
|
:host => host,
|
27
27
|
:port => port,
|
28
28
|
}
|
29
|
-
|
29
|
+
if method
|
30
|
+
config[:encryption] = { :method => method }
|
31
|
+
config[:encryption][:tls_options] = @tls_options if @tls_options
|
32
|
+
end
|
30
33
|
begin
|
31
34
|
uri = construct_uri(host, port, method == :simple_tls)
|
32
35
|
with_start_tls = method == :start_tls
|
33
36
|
info = {:uri => uri, :with_start_tls => with_start_tls}
|
34
37
|
[log("connect", info) {Net::LDAP::Connection.new(config)},
|
35
38
|
uri, with_start_tls]
|
36
|
-
rescue Net::LDAP::
|
37
|
-
raise ConnectionError,
|
39
|
+
rescue Net::LDAP::ConnectionError => error
|
40
|
+
raise ConnectionError, error.message
|
41
|
+
rescue Net::LDAP::Error => error
|
42
|
+
message = "#{error.class}: #{error.message}"
|
43
|
+
raise ConnectionError, message, caller(0) + error.backtrace
|
38
44
|
end
|
39
45
|
end
|
40
46
|
end
|
@@ -50,7 +56,7 @@ module ActiveLdap
|
|
50
56
|
def bind(options={})
|
51
57
|
begin
|
52
58
|
super
|
53
|
-
rescue Net::LDAP::
|
59
|
+
rescue Net::LDAP::Error
|
54
60
|
raise AuthenticationError, $!.message
|
55
61
|
end
|
56
62
|
end
|
@@ -63,25 +69,16 @@ module ActiveLdap
|
|
63
69
|
end
|
64
70
|
|
65
71
|
def search(options={})
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
else
|
70
|
-
paged_results_supported = false
|
71
|
-
end
|
72
|
-
super(options) do |base, scope, filter, attrs, limit|
|
72
|
+
super(options) do |search_options|
|
73
|
+
scope = search_options[:scope]
|
74
|
+
info = search_options.merge(scope: scope_name(scope))
|
73
75
|
args = {
|
74
|
-
:
|
75
|
-
:
|
76
|
-
:
|
77
|
-
:attributes
|
78
|
-
:
|
79
|
-
:
|
80
|
-
}
|
81
|
-
info = {
|
82
|
-
:base => base, :scope => scope_name(scope),
|
83
|
-
:filter => filter, :attributes => attrs, :limit => limit,
|
84
|
-
:paged_results_supported => paged_results_supported,
|
76
|
+
base: search_options[:base],
|
77
|
+
scope: scope,
|
78
|
+
filter: search_options[:filter],
|
79
|
+
attributes: search_options[:attributes],
|
80
|
+
size: search_options[:limit],
|
81
|
+
paged_searcheds_supported: search_options[:paged_results_supported],
|
85
82
|
}
|
86
83
|
execute(:search, info, args) do |entry|
|
87
84
|
attributes = {}
|
@@ -148,8 +145,13 @@ module ActiveLdap
|
|
148
145
|
result = log(name, info) do
|
149
146
|
begin
|
150
147
|
@connection.send(method, *args, &block)
|
151
|
-
rescue
|
152
|
-
|
148
|
+
rescue SystemCallError => error
|
149
|
+
message = "#{error.class}: #{error.message}"
|
150
|
+
raise ConnectionError, message, caller(0) + error.backtrace
|
151
|
+
rescue Net::LDAP::ResponseMissingOrInvalidError => error
|
152
|
+
message = "#{error.class}: #{error.message}"
|
153
|
+
message << ": connection may be timed out"
|
154
|
+
raise ConnectionError, message, caller(0) + error.backtrace
|
153
155
|
end
|
154
156
|
end
|
155
157
|
message = nil
|
@@ -75,15 +75,15 @@ module ActiveLdap
|
|
75
75
|
association_class = Association::BelongsTo
|
76
76
|
opts[:foreign_key_name] ||= "#{association_id}_id"
|
77
77
|
|
78
|
-
before_save
|
79
|
-
if
|
80
|
-
association = @#{association_id}
|
78
|
+
before_save do
|
79
|
+
if instance_variable_defined?(:"@#{association_id}")
|
80
|
+
association = instance_variable_get(:"@#{association_id}")
|
81
81
|
if association and association.updated?
|
82
82
|
self[association.__send__(:primary_key)] =
|
83
|
-
association[
|
83
|
+
association[opts[:foreign_key_name]]
|
84
84
|
end
|
85
85
|
end
|
86
|
-
|
86
|
+
end
|
87
87
|
end
|
88
88
|
|
89
89
|
association_accessor(association_id) do |target|
|