ruby-activeldap 0.6.0 → 0.7.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.
- data/lib/activeldap.rb +11 -7
- data/lib/activeldap/base.rb +207 -168
- data/lib/activeldap/configuration.rb +19 -3
- data/lib/activeldap/ldap.rb +26 -0
- metadata +33 -27
data/lib/activeldap.rb
CHANGED
@@ -469,6 +469,7 @@
|
|
469
469
|
# Most of these are obvious, but I'll step through them for completeness:
|
470
470
|
# * :host defines the LDAP server hostname to connect to.
|
471
471
|
# * :port defines the LDAP server port to connect to.
|
472
|
+
# * :method defines the type of connection - :tls, :ssl, :plain
|
472
473
|
# * :base specifies the LDAP search base to use with the prefixes defined in all
|
473
474
|
# subclasses.
|
474
475
|
# * :bind_format specifies what your server expects when attempting to bind with
|
@@ -478,15 +479,17 @@
|
|
478
479
|
# * :user gives the username to substitute into bind_format for binding with
|
479
480
|
# credentials
|
480
481
|
# * :password_block, if defined, give the Proc block for acquiring the password
|
482
|
+
# * :password, if defined, give the user's password as a String
|
483
|
+
# * :store_password indicates whether the password should be stored, or if used
|
484
|
+
# whether the :password_block should be called on each reconnect.
|
481
485
|
# * :allow_anonymous determines whether anonymous binding is allowed if other
|
482
486
|
# bind methods fail
|
487
|
+
# * :try_sasl, when true, tells ActiveLDAP to attempt a SASL-GSSAPI bind
|
488
|
+
# * :sasl_quiet, when true, tells the SASL libraries to not spew messages to STDOUT
|
483
489
|
#
|
484
490
|
# Base.connect both connects and binds in one step. It follows roughly the following approach:
|
485
491
|
#
|
486
|
-
# * Connect to host:port
|
487
|
-
# * Try TLS.
|
488
|
-
# * If that fails try SSL.
|
489
|
-
# * If that fails try no encryption.
|
492
|
+
# * Connect to host:port using :method
|
490
493
|
#
|
491
494
|
# * If user and password_block, attempt to bind with credentials.
|
492
495
|
# * If that fails or no password_block and anonymous allowed, attempt to bind
|
@@ -546,7 +549,7 @@
|
|
546
549
|
# === Others
|
547
550
|
#
|
548
551
|
# Other exceptions may be raised by the Ruby/LDAP module, or by other subsystems.
|
549
|
-
# If you get one of these exceptions and
|
552
|
+
# If you get one of these exceptions and think it should be wrapped, write me an
|
550
553
|
# email and let me know where it is and what you expected. For faster results,
|
551
554
|
# email a patch!
|
552
555
|
#
|
@@ -902,14 +905,15 @@
|
|
902
905
|
# Blanket warning hiding. Remove for debugging
|
903
906
|
$VERBOSE, verbose = false, $VERBOSE
|
904
907
|
|
908
|
+
require 'activeldap/ldap'
|
909
|
+
require 'activeldap/schema2'
|
905
910
|
require 'activeldap/base'
|
906
911
|
require 'activeldap/associations'
|
907
912
|
require 'activeldap/configuration'
|
908
|
-
require 'activeldap/schema2'
|
909
913
|
|
910
914
|
|
911
915
|
module ActiveLDAP
|
912
|
-
VERSION = "0.
|
916
|
+
VERSION = "0.7.0"
|
913
917
|
end
|
914
918
|
|
915
919
|
ActiveLDAP::Base.class_eval do
|
data/lib/activeldap/base.rb
CHANGED
@@ -50,6 +50,12 @@ module ActiveLDAP
|
|
50
50
|
class AttributeEmpty < RuntimeError
|
51
51
|
end
|
52
52
|
|
53
|
+
# ConfigurationError
|
54
|
+
#
|
55
|
+
# An exception raised when there is a problem with Base.connect arguments
|
56
|
+
class ConfigurationError < RuntimeError
|
57
|
+
end
|
58
|
+
|
53
59
|
# DeleteError
|
54
60
|
#
|
55
61
|
# An exception raised when an ActiveLDAP delete action fails
|
@@ -102,6 +108,7 @@ module ActiveLDAP
|
|
102
108
|
@@config = nil # Container for current connection settings
|
103
109
|
@@schema = nil # LDAP server's schema
|
104
110
|
@@conn = nil # LDAP connection
|
111
|
+
@@reconnect_attempts = 0 # Number of reconnects attempted
|
105
112
|
|
106
113
|
# Driver generator
|
107
114
|
#
|
@@ -110,6 +117,7 @@ module ActiveLDAP
|
|
110
117
|
# is really just a proof of concept and has not truly useful purpose.
|
111
118
|
# example: Base.create_object(:class => "user", :dnattr => "uid", :classes => ['top'])
|
112
119
|
#
|
120
|
+
# THIS METHOD IS DANGEROUS. INPUT IS NOT SANITIZED.
|
113
121
|
def Base.create_object(config={})
|
114
122
|
# Just upcase the first letter of the new class name
|
115
123
|
str = config[:class]
|
@@ -160,7 +168,7 @@ module ActiveLDAP
|
|
160
168
|
|
161
169
|
self.class.module_eval <<-"end_eval"
|
162
170
|
class ::#{class_name} < ActiveLDAP::Base
|
163
|
-
ldap_mapping :dnattr => "#{attr}, :prefix => "#{prefix}", :classes =>
|
171
|
+
ldap_mapping :dnattr => "#{attr}", :prefix => "#{prefix}", :classes => #{classes}
|
164
172
|
#{belongs_to.join("\n")}
|
165
173
|
#{has_many.join("\n")}
|
166
174
|
end
|
@@ -177,30 +185,33 @@ module ActiveLDAP
|
|
177
185
|
# :bind_format specifies the string to substitute the username into on bind. e.g. uid=%s,ou=People,dc=dataspill,dc=org. Overrides @@bind_format.
|
178
186
|
# :password_block specifies a Proc object that will yield a String to be used as the password when called.
|
179
187
|
# :logger specifies a preconfigured Log4r::Logger to be used for all logging
|
180
|
-
# :host
|
181
|
-
# :port
|
188
|
+
# :host sets the LDAP server hostname
|
189
|
+
# :port sets the LDAP server port
|
182
190
|
# :base overwrites Base.base - this affects EVERYTHING
|
183
191
|
# :try_sasl indicates that a SASL bind should be attempted when binding to the server (default: false)
|
184
192
|
# :allow_anonymous indicates that a true anonymous bind is allowed when trying to bind to the server (default: true)
|
185
|
-
# :retries - indicates the number of attempts to reconnect that will be undertaken when a stale connection occurs.
|
186
|
-
|
193
|
+
# :retries - indicates the number of attempts to reconnect that will be undertaken when a stale connection occurs. -1 means infinite.
|
194
|
+
# :sasl_quiet - if true, sets @sasl_quiet on the Ruby/LDAP connection
|
195
|
+
# :method - whether to use :ssl, :tls, or :plain (unencrypted)
|
196
|
+
# :retry_wait - seconds to wait before retrying a connection
|
197
|
+
# :ldap_scope - dictates how to find objects. ONELEVEL by default to avoid dn_attr collisions across OUs. Think before changing.
|
198
|
+
# See lib/configuration.rb for defaults for each option
|
199
|
+
def Base.connect(config={})
|
187
200
|
# Process config
|
188
201
|
# Class options
|
189
202
|
## These will be replace by configuration.rb defaults if defined
|
190
|
-
@@config =
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
end_eval
|
203
|
+
@@config = DEFAULT_CONFIG.dup
|
204
|
+
config.keys.each do |key|
|
205
|
+
if key == :base
|
206
|
+
# Scrub before inserting
|
207
|
+
base = config[:base].gsub(/['}{#]/, '')
|
208
|
+
Base.class_eval("def Base.base();'#{base}';end")
|
209
|
+
else
|
210
|
+
@@config[key] = config[key]
|
211
|
+
end
|
200
212
|
end
|
201
|
-
|
202
|
-
|
203
|
-
@@logger = config[:logger] || nil
|
213
|
+
# Assign a easier name for the logger
|
214
|
+
@@logger = @@config[:logger] || nil
|
204
215
|
# Setup default logger to console
|
205
216
|
if @@logger.nil?
|
206
217
|
@@logger = Log4r::Logger.new('activeldap')
|
@@ -209,30 +220,13 @@ module ActiveLDAP
|
|
209
220
|
@@logger.add('console')
|
210
221
|
end
|
211
222
|
|
212
|
-
#
|
213
|
-
|
214
|
-
password_block = nil
|
215
|
-
@@config[:allow_anonymous] = true
|
216
|
-
@@config[:try_sasl] = false
|
217
|
-
|
218
|
-
@@config[:user] = config[:user] || user
|
219
|
-
@@config[:allow_anonymous] = config[:allow_anonymous] if config.has_key? :allow_anonymous
|
220
|
-
@@config[:try_sasl] = config[:try_sasl]
|
221
|
-
@@config[:password_block] = config[:password_block] if config.has_key? :password_block
|
222
|
-
|
223
|
-
# Setup bind credentials
|
224
|
-
@@config[:user] = ENV['USER'] unless @@config[:user]
|
223
|
+
# Reset for the new connection
|
224
|
+
@@reconnect_attempts = 0
|
225
225
|
|
226
|
+
# Make the connection.
|
226
227
|
do_connect()
|
227
|
-
|
228
|
-
# Load Schema (if not straight SSL...)
|
229
|
-
begin
|
230
|
-
@@schema = @@conn.schema() if @@schema.nil?
|
231
|
-
rescue => detail
|
232
|
-
raise ConnectionError, "#{detail.exception} - LDAP connection failure, or server does not support schema queries."
|
233
|
-
end
|
234
228
|
|
235
|
-
#
|
229
|
+
# Make irb users happy with a 'true'
|
236
230
|
return true
|
237
231
|
end # Base.connect
|
238
232
|
|
@@ -260,6 +254,56 @@ module ActiveLDAP
|
|
260
254
|
@@conn = conn
|
261
255
|
end
|
262
256
|
|
257
|
+
# Attempts to reconnect up to the number of times allowed
|
258
|
+
# If forced, try once then fail with ConnectionError if not connected.
|
259
|
+
def Base.reconnect(force=false)
|
260
|
+
not_connected = true
|
261
|
+
while not_connected
|
262
|
+
# Just to be clean, unbind if possible
|
263
|
+
begin
|
264
|
+
@@conn.unbind() if not @@conn.nil? and @@conn.bound?
|
265
|
+
rescue
|
266
|
+
# Ignore complaints.
|
267
|
+
end
|
268
|
+
@@conn = nil
|
269
|
+
|
270
|
+
if @@config[:retries] == -1 or force == true
|
271
|
+
|
272
|
+
|
273
|
+
# Reset the attempts if this was forced.
|
274
|
+
@@reconnect_attempts = 0 if @@reconnect_attempts != 0
|
275
|
+
begin
|
276
|
+
do_connect()
|
277
|
+
not_connected = false
|
278
|
+
rescue => detail
|
279
|
+
@@logger.error("Reconnect to server failed: #{detail.exception}")
|
280
|
+
@@logger.error("Reconnect to server failed backtrace: #{detail.backtrace}")
|
281
|
+
# Do not loop if forced
|
282
|
+
raise ConnectionError, detail.message if force
|
283
|
+
end
|
284
|
+
elsif @@reconnect_attempts < @@config[:retries]
|
285
|
+
|
286
|
+
@@reconnect_attempts += 1
|
287
|
+
begin
|
288
|
+
do_connect()
|
289
|
+
not_connected = false
|
290
|
+
# Reset to 0 if a connection was made.
|
291
|
+
@@reconnect_attempts = 0
|
292
|
+
rescue => detail
|
293
|
+
@@logger.error("Reconnect to server failed: #{detail.exception}")
|
294
|
+
@@logger.error("Reconnect to server failed backtrace: #{detail.backtrace}")
|
295
|
+
end
|
296
|
+
else
|
297
|
+
# Raise a warning
|
298
|
+
raise ConnectionError, 'Giving up trying to reconnect to LDAP server.'
|
299
|
+
end
|
300
|
+
|
301
|
+
# Sleep before looping
|
302
|
+
sleep @@config[:retry_wait]
|
303
|
+
end
|
304
|
+
return true
|
305
|
+
end
|
306
|
+
|
263
307
|
# Return the schema object
|
264
308
|
def Base.schema
|
265
309
|
@@schema
|
@@ -286,7 +330,6 @@ module ActiveLDAP
|
|
286
330
|
values = []
|
287
331
|
config[:attrs] = config[:attrs].to_a # just in case
|
288
332
|
|
289
|
-
tries = 0
|
290
333
|
begin
|
291
334
|
@@conn.search(config[:base], config[:scope], config[:filter], config[:attrs]) do |m|
|
292
335
|
res = {}
|
@@ -301,14 +344,9 @@ module ActiveLDAP
|
|
301
344
|
rescue RuntimeError => detail
|
302
345
|
#TODO# Check for 'No message' when retrying
|
303
346
|
# The connection may have gone stale. Let's reconnect and retry.
|
304
|
-
if
|
305
|
-
|
306
|
-
|
307
|
-
end
|
308
|
-
tries += 1
|
309
|
-
# Reconnect and rebind.
|
310
|
-
do_connect()
|
311
|
-
retry
|
347
|
+
retry if Base.reconnect()
|
348
|
+
# Do nothing on failure
|
349
|
+
|
312
350
|
end
|
313
351
|
return values
|
314
352
|
end
|
@@ -350,10 +388,9 @@ module ActiveLDAP
|
|
350
388
|
|
351
389
|
matches = []
|
352
390
|
|
353
|
-
tries = 0
|
354
391
|
begin
|
355
392
|
# Get some attributes
|
356
|
-
@@conn.search(base(),
|
393
|
+
@@conn.search(base(), @@config[:ldap_scope], "(#{attr}=#{val})") do |m|
|
357
394
|
# Extract the dnattr value
|
358
395
|
dnval = m.dn.split(/,/)[0].split(/=/)[1]
|
359
396
|
|
@@ -364,22 +401,17 @@ module ActiveLDAP
|
|
364
401
|
end
|
365
402
|
end
|
366
403
|
rescue RuntimeError => detail
|
367
|
-
#
|
368
|
-
#
|
369
|
-
if
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
tries += 1
|
374
|
-
# reconnect and rebind.
|
375
|
-
do_connect()
|
376
|
-
retry
|
404
|
+
#TODO# Check for 'No message' when retrying
|
405
|
+
# The connection may have gone stale. Let's reconnect and retry.
|
406
|
+
retry if Base.reconnect()
|
407
|
+
|
408
|
+
# Do nothing on failure
|
409
|
+
|
377
410
|
end
|
378
411
|
return nil
|
379
412
|
end
|
380
413
|
private_class_method :find
|
381
414
|
|
382
|
-
|
383
415
|
# find_all
|
384
416
|
#
|
385
417
|
# Finds all matches for value where |value| is the value of some
|
@@ -412,10 +444,9 @@ module ActiveLDAP
|
|
412
444
|
|
413
445
|
matches = []
|
414
446
|
|
415
|
-
tries = 0
|
416
447
|
begin
|
417
448
|
# Get some attributes
|
418
|
-
@@conn.search(base(),
|
449
|
+
@@conn.search(base(), @@config[:ldap_scope],
|
419
450
|
"(#{attr}=#{val})") do |m|
|
420
451
|
# Extract the dnattr value
|
421
452
|
dnval = m.dn.split(/,/)[0].split(/=/)[1]
|
@@ -427,19 +458,12 @@ module ActiveLDAP
|
|
427
458
|
end
|
428
459
|
end
|
429
460
|
rescue RuntimeError => detail
|
430
|
-
#
|
431
|
-
|
432
|
-
|
461
|
+
#TODO# Check for 'No message' when retrying
|
462
|
+
# The connection may have gone stale. Let's reconnect and retry.
|
463
|
+
retry if Base.reconnect()
|
433
464
|
|
434
|
-
#
|
435
|
-
|
436
|
-
# do nothing on failure
|
437
|
-
|
438
|
-
end
|
439
|
-
tries += 1
|
440
|
-
# reconnect and rebind.
|
441
|
-
do_connect()
|
442
|
-
retry
|
465
|
+
# Do nothing on failure
|
466
|
+
|
443
467
|
end
|
444
468
|
return matches
|
445
469
|
end
|
@@ -499,13 +523,16 @@ module ActiveLDAP
|
|
499
523
|
def initialize(val)
|
500
524
|
@exists = false
|
501
525
|
# Try a default connection if none made explicitly
|
502
|
-
|
526
|
+
if Base.connection.nil? and @@reconnect_attempts < @@config[:retries]
|
503
527
|
# Use @@config if it has been prepopulated and the conn is down.
|
504
528
|
if @@config
|
505
|
-
ActiveLDAP::Base.
|
529
|
+
ActiveLDAP::Base.reconnect
|
506
530
|
else
|
507
531
|
ActiveLDAP::Base.connect
|
508
532
|
end
|
533
|
+
elsif Base.connection.nil?
|
534
|
+
@@logger.error('Attempted to initialize a new object with no connection')
|
535
|
+
raise ConnectionError, 'Number of reconnect attempts exceeded.'
|
509
536
|
end
|
510
537
|
if val.class == LDAP::Entry
|
511
538
|
# Call import, which is basically initialize
|
@@ -543,10 +570,9 @@ module ActiveLDAP
|
|
543
570
|
@dn = "#{dnattr()}=#{val},#{base()}"
|
544
571
|
|
545
572
|
# Search for the existing entry
|
546
|
-
tries = 0
|
547
573
|
begin
|
548
574
|
# Get some attributes
|
549
|
-
Base.connection.search(base(),
|
575
|
+
Base.connection.search(base(), @@config[:ldap_scope], "(#{dnattr()}=#{val})") do |m|
|
550
576
|
@exists = true
|
551
577
|
# Save DN
|
552
578
|
@dn = m.dn
|
@@ -568,17 +594,13 @@ module ActiveLDAP
|
|
568
594
|
end
|
569
595
|
end
|
570
596
|
rescue RuntimeError => detail
|
571
|
-
#
|
572
|
-
#
|
573
|
-
if
|
574
|
-
|
575
|
-
|
576
|
-
|
577
|
-
|
578
|
-
else
|
579
|
-
@@logger.error('new: unable to search for entry')
|
580
|
-
raise detail
|
581
|
-
end
|
597
|
+
#TODO# Check for 'No message' when retrying
|
598
|
+
# The connection may have gone stale. Let's reconnect and retry.
|
599
|
+
retry if Base.reconnect()
|
600
|
+
|
601
|
+
# Do nothing on failure
|
602
|
+
@@logger.error('new: unable to search for entry')
|
603
|
+
raise detail
|
582
604
|
rescue LDAP::ResultError
|
583
605
|
end
|
584
606
|
end
|
@@ -678,26 +700,19 @@ module ActiveLDAP
|
|
678
700
|
|
679
701
|
end
|
680
702
|
|
681
|
-
|
682
703
|
# delete
|
683
704
|
#
|
684
705
|
# Delete this entry from LDAP
|
685
706
|
def delete
|
686
707
|
|
687
|
-
tries = 0
|
688
708
|
begin
|
689
709
|
@@conn.delete(@dn)
|
690
710
|
@exists = false
|
691
711
|
rescue RuntimeError => detail
|
692
712
|
#todo# check for 'no message' when retrying
|
693
713
|
# the connection may have gone stale. let's reconnect and retry.
|
694
|
-
if
|
695
|
-
|
696
|
-
end
|
697
|
-
tries += 1
|
698
|
-
# reconnect and rebind.
|
699
|
-
do_connect()
|
700
|
-
retry
|
714
|
+
retry if Base.reconnect()
|
715
|
+
raise DeleteError, "Failed to delete LDAP entry: '#{@dn}'"
|
701
716
|
rescue LDAP::ResultError => detail
|
702
717
|
raise DeleteError, "Failed to delete LDAP entry: '#{@dn}'"
|
703
718
|
end
|
@@ -823,7 +838,6 @@ module ActiveLDAP
|
|
823
838
|
end
|
824
839
|
end
|
825
840
|
|
826
|
-
tries = 0
|
827
841
|
begin
|
828
842
|
|
829
843
|
@@conn.modify(@dn, entry)
|
@@ -831,13 +845,8 @@ module ActiveLDAP
|
|
831
845
|
rescue RuntimeError => detail
|
832
846
|
#todo# check for 'no message' when retrying
|
833
847
|
# the connection may have gone stale. let's reconnect and retry.
|
834
|
-
if
|
835
|
-
|
836
|
-
end
|
837
|
-
tries += 1
|
838
|
-
# reconnect and rebind.
|
839
|
-
do_connect()
|
840
|
-
retry
|
848
|
+
retry if Base.reconnect()
|
849
|
+
raise WriteError, "Could not update LDAP entry: #{detail}"
|
841
850
|
rescue => detail
|
842
851
|
raise WriteError, "Could not update LDAP entry: #{detail}"
|
843
852
|
end
|
@@ -861,21 +870,15 @@ module ActiveLDAP
|
|
861
870
|
entry.push(LDAP.mod(LDAP::LDAP_MOD_ADD|binary, pair[0], pair[1]))
|
862
871
|
end
|
863
872
|
end
|
864
|
-
tries = 0
|
865
873
|
begin
|
866
874
|
|
867
875
|
@@conn.add(@dn, entry)
|
868
876
|
|
869
877
|
@exists = true
|
870
|
-
rescue RuntimeError =>
|
878
|
+
rescue RuntimeError => detail
|
871
879
|
# The connection may have gone stale. Let's reconnect and retry.
|
872
|
-
if
|
873
|
-
|
874
|
-
end
|
875
|
-
tries += 1
|
876
|
-
# Reconnect and rebind.
|
877
|
-
do_connect()
|
878
|
-
retry
|
880
|
+
retry if Base.reconnect()
|
881
|
+
raise WriteError, "Could not add LDAP entry[#{Base.connection.err2string(Base.connection.err)}]: #{detail}"
|
879
882
|
rescue LDAP::ResultError => detail
|
880
883
|
raise WriteError, "Could not add LDAP entry[#{Base.connection.err2string(Base.connection.err)}]: #{detail}"
|
881
884
|
end
|
@@ -1138,66 +1141,65 @@ module ActiveLDAP
|
|
1138
1141
|
# Performs the actually connection. This separate so that it may
|
1139
1142
|
# be called to refresh stale connections.
|
1140
1143
|
def Base.do_connect()
|
1141
|
-
|
1142
|
-
|
1143
|
-
|
1144
|
-
|
1145
|
-
|
1146
|
-
# SSL using START_TLS
|
1144
|
+
begin
|
1145
|
+
case @@config[:method]
|
1146
|
+
when :ssl
|
1147
|
+
@@conn = LDAP::SSLConn.new(@@config[:host], @@config[:port], false)
|
1148
|
+
when :tls
|
1147
1149
|
@@conn = LDAP::SSLConn.new(@@config[:host], @@config[:port], true)
|
1148
|
-
|
1149
|
-
@@
|
1150
|
-
|
1151
|
-
|
1152
|
-
|
1153
|
-
|
1154
|
-
|
1155
|
-
|
1156
|
-
|
1157
|
-
|
1158
|
-
|
1159
|
-
|
1160
|
-
end
|
1161
|
-
|
1150
|
+
when :plain
|
1151
|
+
@@conn = LDAP::Conn.new(@@config[:host], @@config[:port])
|
1152
|
+
else
|
1153
|
+
raise ConfigurationError,"#{@@config[:method]} is not one of the available connect methods :ssl, :tls, or :plain"
|
1154
|
+
end
|
1155
|
+
rescue ConfigurationError => e
|
1156
|
+
# Pass through
|
1157
|
+
raise e
|
1158
|
+
rescue => e
|
1159
|
+
@@logger.error("Failed to connect using #{@@config[:method]}")
|
1160
|
+
raise e
|
1161
|
+
end
|
1162
1162
|
|
1163
|
-
|
1164
|
-
|
1163
|
+
# Enforce LDAPv3
|
1164
|
+
@@conn.set_option(LDAP::LDAP_OPT_PROTOCOL_VERSION, 3)
|
1165
1165
|
|
1166
|
-
|
1167
|
-
|
1168
|
-
rescue => e
|
1169
|
-
# Retry
|
1170
|
-
tries += 1
|
1171
|
-
raise e if tries > @@config[:retries]
|
1172
|
-
retry
|
1173
|
-
end
|
1174
|
-
end
|
1166
|
+
# Authenticate
|
1167
|
+
do_bind
|
1175
1168
|
|
1169
|
+
# Retrieve the schema. We need this to automagically determine attributes
|
1170
|
+
begin
|
1171
|
+
@@schema = @@conn.schema() if @@schema.nil?
|
1172
|
+
rescue => e
|
1173
|
+
@@logger.error("Failed to retrieve the schema (#{@@config[:method]})")
|
1174
|
+
@@logger.error("Schema failure exception: #{e.exception}")
|
1175
|
+
@@logger.error("Schema failure backtrace: #{e.backtrace}")
|
1176
|
+
raise ConnectionError, "#{e.exception} - LDAP connection failure, or server does not support schema queries."
|
1177
|
+
end
|
1178
|
+
|
1179
|
+
|
1180
|
+
end
|
1176
1181
|
|
1177
1182
|
# Wrapper all bind activity
|
1178
1183
|
def Base.do_bind()
|
1179
1184
|
bind_dn = @@config[:bind_format] % [@@config[:user]]
|
1180
|
-
if @@config[:password_block]
|
1181
|
-
password = @@config[:password_block].call
|
1182
|
-
@@config[:password_block] = Proc.new { password }
|
1183
|
-
end
|
1184
|
-
|
1185
1185
|
# Rough bind loop:
|
1186
1186
|
# Attempt 1: SASL if available
|
1187
1187
|
# Attempt 2: SIMPLE with credentials if password block
|
1188
1188
|
# Attempt 3: SIMPLE ANONYMOUS if 1 and 2 fail (or pwblock returns '')
|
1189
|
-
|
1190
|
-
|
1191
|
-
|
1192
|
-
|
1193
|
-
|
1194
|
-
|
1195
|
-
|
1189
|
+
if @@config[:try_sasl] and do_sasl_bind(bind_dn)
|
1190
|
+
@@logger.info('Bound SASL')
|
1191
|
+
elsif do_simple_bind(bind_dn)
|
1192
|
+
@@logger.info('Bound simple')
|
1193
|
+
elsif @@config[:allow_anonymous] and do_anonymous_bind(bind_dn)
|
1194
|
+
@@logger.info('Bound simple')
|
1195
|
+
else
|
1196
|
+
@@logger.error('Failed to bind using any available method')
|
1197
|
+
raise *LDAP::err2exception(@@conn.err) if @@conn.err != 0
|
1196
1198
|
end
|
1197
|
-
|
1199
|
+
|
1200
|
+
return @@conn.bound?
|
1198
1201
|
end
|
1199
1202
|
|
1200
|
-
|
1201
1203
|
# Base.do_anonymous_bind
|
1202
1204
|
#
|
1203
1205
|
# Bind to LDAP with the given DN, but with no password. (anonymous!)
|
@@ -1206,26 +1208,62 @@ module ActiveLDAP
|
|
1206
1208
|
begin
|
1207
1209
|
@@conn.bind()
|
1208
1210
|
return true
|
1209
|
-
rescue
|
1211
|
+
rescue => e
|
1212
|
+
|
1213
|
+
|
1210
1214
|
|
1211
1215
|
@@logger.warn "Warning: Anonymous authentication failed."
|
1216
|
+
@@logger.warn "message: #{e.message}"
|
1212
1217
|
return false
|
1213
1218
|
end
|
1214
1219
|
end
|
1215
1220
|
|
1216
1221
|
# Base.do_simple_bind
|
1217
1222
|
#
|
1218
|
-
# Bind to LDAP with the given DN and
|
1223
|
+
# Bind to LDAP with the given DN and password
|
1219
1224
|
def Base.do_simple_bind(bind_dn)
|
1220
|
-
|
1225
|
+
# Bail if we have no password or password block
|
1226
|
+
if not @@config[:password_block].nil? and not @@config[:password].nil?
|
1227
|
+
return false
|
1228
|
+
end
|
1229
|
+
|
1230
|
+
# TODO: Give a warning to reconnect users with password clearing
|
1231
|
+
# Get the passphrase for the first time, or anew if we aren't storing
|
1232
|
+
password = ''
|
1233
|
+
if not @@config[:password].nil?
|
1234
|
+
password = @@config[:password]
|
1235
|
+
elsif not @@config[:password_block].nil?
|
1236
|
+
unless @@config[:password_block].respond_to?(:call)
|
1237
|
+
@@logger.error('Skipping simple bind: ' +
|
1238
|
+
':password_block not nil or Proc object. Ignoring.')
|
1239
|
+
return false
|
1240
|
+
end
|
1241
|
+
password = @@config[:password_block].call
|
1242
|
+
else
|
1243
|
+
@@logger.error('Skipping simple bind: ' +
|
1244
|
+
':password_block and :password options are empty.')
|
1245
|
+
return false
|
1246
|
+
end
|
1247
|
+
|
1221
1248
|
begin
|
1222
|
-
@@conn.bind(bind_dn,
|
1223
|
-
|
1224
|
-
rescue
|
1249
|
+
@@conn.bind(bind_dn, password)
|
1250
|
+
rescue => e
|
1225
1251
|
|
1226
|
-
|
1252
|
+
# TODO: replace this with LDAP::err2exception()
|
1253
|
+
if @@conn.err == LDAP::LDAP_SERVER_DOWN
|
1254
|
+
@@logger.error "Warning: " + e.message
|
1255
|
+
else
|
1256
|
+
@@logger.warn "Warning: SIMPLE authentication failed."
|
1257
|
+
end
|
1227
1258
|
return false
|
1228
1259
|
end
|
1260
|
+
# Store the password for quick reference later
|
1261
|
+
if @@config[:store_password]
|
1262
|
+
@@config[:password] = password
|
1263
|
+
elsif @@config[:store_password] == false
|
1264
|
+
@@config[:password] = nil
|
1265
|
+
end
|
1266
|
+
return true
|
1229
1267
|
end
|
1230
1268
|
|
1231
1269
|
# Base.do_sasl_bind
|
@@ -1240,6 +1278,7 @@ module ActiveLDAP
|
|
1240
1278
|
# TODO: Investigate further SASL support
|
1241
1279
|
if mechanisms.respond_to? :member? and mechanisms.member? 'GSSAPI'
|
1242
1280
|
begin
|
1281
|
+
@@conn.sasl_quiet = @@config[:sasl_quiet] if @@config.has_key?(:sasl_quiet)
|
1243
1282
|
@@conn.sasl_bind(bind_dn, 'GSSAPI')
|
1244
1283
|
return true
|
1245
1284
|
rescue
|
@@ -6,9 +6,25 @@ module ActiveLDAP
|
|
6
6
|
# ActiveLDAP to work with your LDAP server. All of these
|
7
7
|
# settings can be passed in at initialization time.
|
8
8
|
module Configuration
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
DEFAULT_CONFIG = {}
|
10
|
+
DEFAULT_CONFIG[:host] = '127.0.0.1'
|
11
|
+
DEFAULT_CONFIG[:port] = 389
|
12
|
+
DEFAULT_CONFIG[:method] = :plain # :ssl, :tls, :plain allowed
|
13
|
+
|
14
|
+
DEFAULT_CONFIG[:bind_format] = "cn=%s,dc=localdomain"
|
15
|
+
DEFAULT_CONFIG[:user] = ENV['USER']
|
16
|
+
DEFAULT_CONFIG[:password_block] = nil
|
17
|
+
DEFAULT_CONFIG[:password] = nil
|
18
|
+
DEFAULT_CONFIG[:store_password] = true
|
19
|
+
DEFAULT_CONFIG[:allow_anonymous] = true
|
20
|
+
DEFAULT_CONFIG[:sasl_quiet] = false
|
21
|
+
DEFAULT_CONFIG[:try_sasl] = false
|
22
|
+
|
23
|
+
DEFAULT_CONFIG[:retries] = 3
|
24
|
+
DEFAULT_CONFIG[:retry_wait] = 3
|
25
|
+
|
26
|
+
DEFAULT_CONFIG[:logger] = nil
|
27
|
+
DEFAULT_CONFIG[:ldap_scope] = LDAP::LDAP_SCOPE_ONELEVEL
|
12
28
|
|
13
29
|
# Make the return value the string that is your LDAP base
|
14
30
|
def Base.base
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# Extensions to Rubu/LDAP to make ActiveLDAP behave better
|
2
|
+
#
|
3
|
+
|
4
|
+
|
5
|
+
|
6
|
+
module LDAP
|
7
|
+
# Creates useful exceptions from err2string output
|
8
|
+
# Returns [exception, message] based on err2string
|
9
|
+
def LDAP.err2exception(errno=0)
|
10
|
+
err = LDAP::err2string(errno)
|
11
|
+
err = err.split(' ').collect {|w| w.capitalize }.join('')
|
12
|
+
err.gsub!(/[^A-Za-z]/, '')
|
13
|
+
# If the exception exists - raise it!
|
14
|
+
begin
|
15
|
+
exc = LDAP.const_get(err)
|
16
|
+
rescue NameError
|
17
|
+
# Doesn't exist :-)
|
18
|
+
LDAP.module_eval(<<-end_module_eval)
|
19
|
+
class #{err} < LDAP::ResultError
|
20
|
+
end
|
21
|
+
end_module_eval
|
22
|
+
exc = LDAP.const_get(err)
|
23
|
+
end
|
24
|
+
return [exc, err2string(errno)]
|
25
|
+
end
|
26
|
+
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
|
-
rubygems_version: 0.8.
|
2
|
+
rubygems_version: 0.8.11
|
3
3
|
specification_version: 1
|
4
4
|
name: ruby-activeldap
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 0.
|
7
|
-
date: 2006-01
|
6
|
+
version: 0.7.0
|
7
|
+
date: 2006-05-03 00:00:00 +01:00
|
8
8
|
summary: Ruby/ActiveLDAP is a object-oriented API to LDAP
|
9
9
|
require_paths:
|
10
|
-
|
10
|
+
- lib
|
11
11
|
email: will@alum.bu.edu
|
12
12
|
homepage: http://projects.dataspill.org/libraries/ruby/activeldap/index.html
|
13
13
|
rubyforge_project: ruby-activeldap
|
@@ -18,37 +18,43 @@ bindir: bin
|
|
18
18
|
has_rdoc: false
|
19
19
|
required_ruby_version: !ruby/object:Gem::Version::Requirement
|
20
20
|
requirements:
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
version: 0.0.0
|
21
|
+
- - ">"
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 0.0.0
|
25
24
|
version:
|
26
25
|
platform: ruby
|
26
|
+
signing_key:
|
27
|
+
cert_chain:
|
27
28
|
authors:
|
28
|
-
|
29
|
+
- Will Drewry
|
29
30
|
files:
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
31
|
+
- lib/activeldap
|
32
|
+
- lib/activeldap.rb
|
33
|
+
- lib/activeldap/associations.rb
|
34
|
+
- lib/activeldap/base.rb
|
35
|
+
- lib/activeldap/configuration.rb
|
36
|
+
- lib/activeldap/ldap.rb
|
37
|
+
- lib/activeldap/schema2.rb
|
36
38
|
test_files: []
|
39
|
+
|
37
40
|
rdoc_options: []
|
41
|
+
|
38
42
|
extra_rdoc_files: []
|
43
|
+
|
39
44
|
executables: []
|
45
|
+
|
40
46
|
extensions: []
|
47
|
+
|
41
48
|
requirements:
|
42
|
-
|
43
|
-
|
49
|
+
- (Open)LDAP server
|
50
|
+
- ruby-ldap = 0.8.2
|
44
51
|
dependencies:
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
version:
|
52
|
+
- !ruby/object:Gem::Dependency
|
53
|
+
name: log4r
|
54
|
+
version_requirement:
|
55
|
+
version_requirements: !ruby/object:Gem::Version::Requirement
|
56
|
+
requirements:
|
57
|
+
- - ">="
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
version: 1.0.4
|
60
|
+
version:
|