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 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 thing it should be wrapped, write me an
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.6.0"
916
+ VERSION = "0.7.0"
913
917
  end
914
918
 
915
919
  ActiveLDAP::Base.class_eval do
@@ -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 => "#{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 overrides the configuration.rb @@host setting with the LDAP server hostname
181
- # :port overrides the configuration.rb @@port setting for the LDAP server 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
- def Base.connect(config={}) # :user, :password_block, :logger
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
- @@config[:host] = config[:host] || @@host
192
- @@config[:port] = config[:port] || @@port
193
- @@config[:retries] = config[:retries] || 3
194
- if config[:base]
195
- Base.class_eval <<-"end_eval"
196
- def Base.base
197
- '#{config[:base]}'
198
- end
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
- @@config[:bind_format] = config[:bind_format] || @@bind_format
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
- # Method options
213
- user = nil
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
- # Cleanly return
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 tries > @@config[:retries]
305
- # Do nothing on failure
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(), LDAP::LDAP_SCOPE_ONELEVEL, "(#{attr}=#{val})") do |m|
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
- #todo# check for 'no message' when retrying
368
- # the connection may have gone stale. let's reconnect and retry.
369
- if tries > @@config[:retries]
370
- # do nothing on failure
371
-
372
- end
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(), LDAP::LDAP_SCOPE_ONELEVEL,
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
- #todo# check for 'no message' when retrying
431
-
432
- #TODO# This is broken because search gives bad messages.
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
- # the connection may have gone stale. let's reconnect and retry.
435
- if tries > @@config[:retries]
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
- unless Base.connection
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.connect(@@config)
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(), LDAP::LDAP_SCOPE_ONELEVEL, "(#{dnattr()}=#{val})") do |m|
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
- #todo# check for 'no message' when retrying
572
- # the connection may have gone stale. let's reconnect and retry.
573
- if tries <= @@config[:retries]
574
- tries += 1
575
- # reconnect and rebind.
576
- do_connect()
577
- retry
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 tries > @@config[:retries]
695
- raise DeleteError, "Failed to delete LDAP entry: '#{@dn}'"
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 tries > @@config[:retries]
835
- raise WriteError, "Could not update LDAP entry: #{detail}"
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 => e
878
+ rescue RuntimeError => detail
871
879
  # The connection may have gone stale. Let's reconnect and retry.
872
- if tries > @@config[:retries]
873
- raise WriteError, "Could not add LDAP entry[#{Base.connection.err2string(Base.connection.err)}]: #{detail}"
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
- # Wrap the whole thing an try retries times
1142
- tries = 0
1143
- begin
1144
- # Connect to LDAP
1145
- begin
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
- rescue
1149
- @@logger.warn "Warning: Failed to connect using TLS!"
1150
- begin
1151
- @@logger.warn "Warning: Attempting SSL connection . . ."
1152
- @@conn = LDAP::SSLConn.new(@@config[:host], @@config[:port], false)
1153
- # HACK: Load the schema here because otherwise you can't tell if the
1154
- # HACK: SSLConn is a real SSL connection.
1155
- @@schema = @@conn.schema() if @@schema.nil?
1156
- rescue
1157
- @@logger.warn "Warning: Attempting unencrypted connection . . ."
1158
- @@conn = LDAP::Conn.new(@@config[:host], @@config[:port])
1159
- end
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
- # Enforce LDAPv3
1164
- @@conn.set_option(LDAP::LDAP_OPT_PROTOCOL_VERSION, 3)
1163
+ # Enforce LDAPv3
1164
+ @@conn.set_option(LDAP::LDAP_OPT_PROTOCOL_VERSION, 3)
1165
1165
 
1166
- # Authenticate
1167
- do_bind
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
- auth = false
1190
- auth = do_sasl_bind(bind_dn) if @@config[:try_sasl]
1191
- auth = do_simple_bind(bind_dn) unless auth
1192
- auth = do_anonymous_bind(bind_dn) if not auth and @@config[:allow_anonymous]
1193
-
1194
- unless auth
1195
- raise AuthenticationError, "All authentication mechanisms failed"
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
- return auth
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 password_block.call()
1223
+ # Bind to LDAP with the given DN and password
1219
1224
  def Base.do_simple_bind(bind_dn)
1220
- return false unless @@config[:password_block].respond_to? :call
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, @@config[:password_block].call())
1223
- return true
1224
- rescue
1249
+ @@conn.bind(bind_dn, password)
1250
+ rescue => e
1225
1251
 
1226
- @@logger.warn "Warning: SIMPLE authentication failed."
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
- @@host = "127.0.0.1"
10
- @@port = 389
11
- @@bind_format = "cn=%s,dc=localdomain"
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.4
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.6.0
7
- date: 2006-01-09
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
- - lib
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
- - !ruby/object:Gem::Version
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
- - Will Drewry
29
+ - Will Drewry
29
30
  files:
30
- - lib/activeldap
31
- - lib/activeldap.rb
32
- - lib/activeldap/associations.rb
33
- - lib/activeldap/base.rb
34
- - lib/activeldap/configuration.rb
35
- - lib/activeldap/schema2.rb
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
- - "(Open)LDAP server"
43
- - ruby-ldap = 0.8.2
49
+ - (Open)LDAP server
50
+ - ruby-ldap = 0.8.2
44
51
  dependencies:
45
- - !ruby/object:Gem::Dependency
46
- name: log4r
47
- version_requirement:
48
- version_requirements: !ruby/object:Gem::Version::Requirement
49
- requirements:
50
- -
51
- - ">="
52
- - !ruby/object:Gem::Version
53
- version: 1.0.4
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: