ruby-activeldap 0.6.0 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
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: