# File lib/active_ldap/adapter/jndi.rb, line 7 7: def jndi_connection(options) 8: require 'active_ldap/adapter/jndi_connection' 9: Jndi.new(options) 10: end
# File lib/active_ldap/adapter/ldap.rb, line 7 7: def ldap_connection(options) 8: require 'active_ldap/adapter/ldap_ext' 9: Ldap.new(options) 10: end
# File lib/active_ldap/adapter/net_ldap.rb, line 9 9: def net_ldap_connection(options) 10: require 'active_ldap/adapter/net_ldap_ext' 11: NetLdap.new(options) 12: end
# File lib/active_ldap/adapter/base.rb, line 23 23: def initialize(configuration={}) 24: @runtime = 0 25: @connection = nil 26: @disconnected = false 27: @bound = false 28: @bind_tried = false 29: @entry_attributes = {} 30: @configuration = configuration.dup 31: @logger = @configuration.delete(:logger) 32: @configuration.assert_valid_keys(VALID_ADAPTER_CONFIGURATION_KEYS) 33: VALID_ADAPTER_CONFIGURATION_KEYS.each do |name| 34: instance_variable_set("@#{name}", configuration[name]) 35: end 36: end
# File lib/active_ldap/adapter/base.rb, line 202 202: def add(dn, entries, options={}) 203: dn = ensure_dn_string(dn) 204: begin 205: operation(options) do 206: yield(dn, entries) 207: end 208: rescue LdapError::NoSuchObject 209: raise EntryNotFound, _("No such entry: %s") % dn 210: rescue LdapError::InvalidDnSyntax 211: raise DistinguishedNameInvalid.new(dn) 212: rescue LdapError::AlreadyExists 213: raise EntryAlreadyExist, _("%s: %s") % [$!.message, dn] 214: rescue LdapError::StrongAuthRequired 215: raise StrongAuthenticationRequired, _("%s: %s") % [$!.message, dn] 216: rescue LdapError::ObjectClassViolation 217: raise RequiredAttributeMissed, _("%s: %s") % [$!.message, dn] 218: rescue LdapError::UnwillingToPerform 219: raise OperationNotPermitted, _("%s: %s") % [$!.message, dn] 220: end 221: end
# File lib/active_ldap/adapter/base.rb, line 67 67: def bind(options={}) 68: @bind_tried = true 69: 70: bind_dn = ensure_dn_string(options[:bind_dn] || @bind_dn) 71: try_sasl = options.has_key?(:try_sasl) ? options[:try_sasl] : @try_sasl 72: if options.has_key?(:allow_anonymous) 73: allow_anonymous = options[:allow_anonymous] 74: else 75: allow_anonymous = @allow_anonymous 76: end 77: options = options.merge(:allow_anonymous => allow_anonymous) 78: 79: # Rough bind loop: 80: # Attempt 1: SASL if available 81: # Attempt 2: SIMPLE with credentials if password block 82: # Attempt 3: SIMPLE ANONYMOUS if 1 and 2 fail (or pwblock returns '') 83: if try_sasl and sasl_bind(bind_dn, options) 84: @logger.info {_('Bound to %s by SASL as %s') % [target, bind_dn]} 85: elsif simple_bind(bind_dn, options) 86: @logger.info {_('Bound to %s by simple as %s') % [target, bind_dn]} 87: elsif allow_anonymous and bind_as_anonymous(options) 88: @logger.info {_('Bound to %s as anonymous') % target} 89: else 90: message = yield if block_given? 91: message ||= _('All authentication methods for %s exhausted.') % target 92: raise AuthenticationError, message 93: end 94: 95: @bound = true 96: @bound 97: end
# File lib/active_ldap/adapter/base.rb, line 104 104: def bind_as_anonymous(options={}) 105: yield 106: end
# File lib/active_ldap/adapter/base.rb, line 112 112: def bound? 113: connecting? and @bound 114: end
# File lib/active_ldap/adapter/base.rb, line 43 43: def connect(options={}) 44: host = options[:host] || @host 45: method = options[:method] || @method || :plain 46: port = options[:port] || @port || ensure_port(method) 47: method = ensure_method(method) 48: @disconnected = false 49: @bound = false 50: @bind_tried = false 51: @connection, @uri, @with_start_tls = yield(host, port, method) 52: prepare_connection(options) 53: bind(options) 54: end
# File lib/active_ldap/adapter/base.rb, line 108 108: def connecting? 109: !@connection.nil? and !@disconnected 110: end
# File lib/active_ldap/adapter/base.rb, line 183 183: def delete(targets, options={}) 184: targets = [targets] unless targets.is_a?(Array) 185: return if targets.empty? 186: begin 187: operation(options) do 188: targets.each do |target| 189: target = ensure_dn_string(target) 190: begin 191: yield(target) 192: rescue LdapError::UnwillingToPerform, LdapError::InsufficientAccess 193: raise OperationNotPermitted, _("%s: %s") % [$!.message, target] 194: end 195: end 196: end 197: rescue LdapError::NoSuchObject 198: raise EntryNotFound, _("No such entry: %s") % target 199: end 200: end
# File lib/active_ldap/adapter/base.rb, line 56 56: def disconnect!(options={}) 57: unbind(options) 58: @connection = @uri = @with_start_tls = nil 59: @disconnected = true 60: end
# File lib/active_ldap/adapter/base.rb, line 146 146: def entry_attribute(object_classes) 147: @entry_attributes[object_classes.uniq.sort] ||= 148: EntryAttribute.new(schema, object_classes) 149: end
# File lib/active_ldap/adapter/base.rb, line 247 247: def log_info(name, runtime_in_seconds, info=nil) 248: return unless @logger 249: return unless @logger.debug? 250: message = "LDAP: #{name} (#{'%.1f' % (runtime_in_seconds * 1000)}ms)" 251: @logger.debug(format_log_entry(message, info)) 252: end
# File lib/active_ldap/adapter/base.rb, line 223 223: def modify(dn, entries, options={}) 224: dn = ensure_dn_string(dn) 225: begin 226: operation(options) do 227: begin 228: yield(dn, entries) 229: rescue LdapError::UnwillingToPerform, LdapError::InsufficientAccess 230: raise OperationNotPermitted, _("%s: %s") % [$!.message, target] 231: end 232: end 233: rescue LdapError::UndefinedType 234: raise 235: rescue LdapError::ObjectClassViolation 236: raise RequiredAttributeMissed, _("%s: %s") % [$!.message, dn] 237: end 238: end
# File lib/active_ldap/adapter/base.rb, line 240 240: def modify_rdn(dn, new_rdn, delete_old_rdn, new_superior, options={}) 241: dn = ensure_dn_string(dn) 242: operation(options) do 243: yield(dn, new_rdn, delete_old_rdn, new_superior) 244: end 245: end
# File lib/active_ldap/adapter/base.rb, line 142 142: def naming_contexts 143: root_dse_values('namingContexts') 144: end
# File lib/active_ldap/adapter/base.rb, line 62 62: def rebind(options={}) 63: unbind(options) if bound? 64: connect(options) 65: end
# File lib/active_ldap/adapter/base.rb, line 38 38: def reset_runtime 39: runtime, @runtime = @runtime, 0 40: runtime 41: end
# File lib/active_ldap/adapter/base.rb, line 116 116: def schema(options={}) 117: @schema ||= operation(options) do 118: base = options[:base] 119: attrs = options[:attributes] 120: 121: attrs ||= [ 122: 'objectClasses', 123: 'attributeTypes', 124: 'matchingRules', 125: 'matchingRuleUse', 126: 'dITStructureRules', 127: 'dITContentRules', 128: 'nameForms', 129: 'ldapSyntaxes', 130: #'extendedAttributeInfo', # if we need RANGE-LOWER/UPPER. 131: ] 132: base ||= root_dse_values('subschemaSubentry', options)[0] 133: base ||= 'cn=schema' 134: dn, attributes = search(:base => base, 135: :scope => :base, 136: :filter => '(objectClass=subschema)', 137: :attributes => attrs).first 138: Schema.new(attributes) 139: end 140: end
# File lib/active_ldap/adapter/base.rb, line 151 151: def search(options={}) 152: filter = parse_filter(options[:filter]) || 'objectClass=*' 153: attrs = options[:attributes] || [] 154: scope = ensure_scope(options[:scope] || @scope) 155: base = options[:base] 156: limit = options[:limit] || 0 157: limit = nil if limit <= 0 158: 159: attrs = attrs.to_a # just in case 160: 161: values = [] 162: callback = Proc.new do |value, block| 163: value = block.call(value) if block 164: values << value 165: end 166: 167: base = ensure_dn_string(base) 168: begin 169: operation(options) do 170: yield(base, scope, filter, attrs, limit, callback) 171: end 172: rescue LdapError::NoSuchObject, LdapError::InvalidDnSyntax 173: # Do nothing on failure 174: @logger.info do 175: args = [$!.class, $!.message, filter, attrs.inspect] 176: _("Ignore error %s(%s): filter %s: attributes: %s") % args 177: end 178: end 179: 180: values 181: end
# File lib/active_ldap/adapter/base.rb, line 556 556: def assert_filter_logical_operator(operator) 557: return if operator.nil? 558: unless filter_logical_operator?(operator) 559: raise ArgumentError, 560: _("invalid logical operator: %s: available operators: %s") % 561: [operator.inspect, LOGICAL_OPERATORS.inspect] 562: end 563: end
Determine if we have exceed the retry limit or not. True is reconnecting is allowed - False if not.
# File lib/active_ldap/adapter/base.rb, line 617 617: def can_reconnect?(options={}) 618: retry_limit = options[:retry_limit] || @retry_limit 619: reconnect_attempts = options[:reconnect_attempts] || 0 620: 621: retry_limit < 0 or reconnect_attempts <= retry_limit 622: end
# File lib/active_ldap/adapter/base.rb, line 535 535: def collection?(object) 536: !object.is_a?(String) and object.respond_to?(:each) 537: end
# File lib/active_ldap/adapter/base.rb, line 468 468: def construct_component(key, value, operator=nil) 469: value, options = extract_filter_value_options(value) 470: comparison_operator = options[:operator] || "=" 471: if collection?(value) 472: return nil if value.empty? 473: operator, value = normalize_array_filter(value, operator) 474: values = [] 475: value.each do |val| 476: if collection?(val) 477: values.concat(val.collect {|v| [key, comparison_operator, v]}) 478: else 479: values << [key, comparison_operator, val] 480: end 481: end 482: values[0] = values[0][1] if filter_logical_operator?(values[0][1]) 483: parse_filter(values, operator) 484: else 485: [ 486: "(", 487: escape_filter_key(key), 488: comparison_operator, 489: escape_filter_value(value, options), 490: ")" 491: ].join 492: end 493: end
# File lib/active_ldap/adapter/base.rb, line 444 444: def construct_components(components, operator) 445: components.collect do |component| 446: if component.is_a?(Array) 447: if filter_logical_operator?(component[0]) 448: parse_filter(component) 449: elsif component.size == 2 450: key, value = component 451: if value.is_a?(Hash) 452: parse_filter(value, key) 453: else 454: construct_component(key, value, operator) 455: end 456: else 457: construct_component(component[0], component[1..1], operator) 458: end 459: elsif component.is_a?(Symbol) 460: assert_filter_logical_operator(component) 461: nil 462: else 463: parse_filter(component, operator) 464: end 465: end 466: end
# File lib/active_ldap/adapter/base.rb, line 520 520: def construct_filter(components, operator=nil) 521: operator = normalize_filter_logical_operator(operator) 522: components = components.compact 523: case components.size 524: when 0 525: nil 526: when 1 527: filter = components[0] 528: filter = "(!#{filter})" if operator == :not 529: filter 530: else 531: "(#{operator == :and ? '&' : '|'}#{components.join})" 532: end 533: end
# File lib/active_ldap/adapter/base.rb, line 642 642: def construct_uri(host, port, ssl) 643: protocol = ssl ? "ldaps" : "ldap" 644: URI.parse("#{protocol}://#{host}:#{port}").to_s 645: end
# File lib/active_ldap/adapter/base.rb, line 694 694: def ensure_dn_string(dn) 695: if dn.is_a?(DN) 696: dn.to_s 697: else 698: dn 699: end 700: end
# File lib/active_ldap/adapter/base.rb, line 255 255: def ensure_port(method) 256: if method == :ssl 257: URI::LDAPS::DEFAULT_PORT 258: else 259: URI::LDAP::DEFAULT_PORT 260: end 261: end
# File lib/active_ldap/adapter/base.rb, line 495 495: def escape_filter_key(key) 496: escape_filter_value(key.to_s) 497: end
# File lib/active_ldap/adapter/base.rb, line 499 499: def escape_filter_value(value, options={}) 500: case value 501: when Numeric, DN 502: value = value.to_s 503: when Time 504: value = Schema::GeneralizedTime.new.normalize_value(value) 505: end 506: value.gsub(/(?:[()\\\00]]|\*\*?)/) do |s| 507: if s == "*" 508: s 509: else 510: s = "*" if s == "**" 511: if s.respond_to?(:getbyte) 512: "\\%02X" % s.getbyte(0) 513: else 514: "\\%02X" % s[0] 515: end 516: end 517: end 518: end
# File lib/active_ldap/adapter/base.rb, line 425 425: def extract_filter_value_options(value) 426: options = {} 427: if value.is_a?(Array) 428: case value[0] 429: when Hash 430: options = value[0] 431: value = value[1] 432: when "=", "~=", "<=", ">=" 433: options[:operator] = value[0] 434: if value.size > 2 435: value = value[1..1] 436: else 437: value = value[1] 438: end 439: end 440: end 441: [value, options] 442: end
# File lib/active_ldap/adapter/base.rb, line 540 540: def filter_logical_operator?(operator) 541: LOGICAL_OPERATORS.include?(operator) 542: end
# File lib/active_ldap/adapter/base.rb, line 674 674: def format_log_entry(message, info=nil) 675: if ActiveLdap::Base.colorize_logging 676: if @@row_even 677: message_color, dump_color = "4;36;1", "0;1" 678: else 679: @@row_even = true 680: message_color, dump_color = "4;35;1", "0" 681: end 682: @@row_even = !@@row_even 683: 684: log_entry = " \e[#{message_color}m#{message}\e[0m" 685: log_entry << ": \e[#{dump_color}m#{info.inspect}\e[0m" if info 686: log_entry 687: else 688: log_entry = message 689: log_entry += ": #{info.inspect}" if info 690: log_entry 691: end 692: end
# File lib/active_ldap/adapter/base.rb, line 656 656: def log(name, info=nil) 657: if block_given? 658: result = nil 659: seconds = Benchmark.realtime {result = yield} 660: @runtime += seconds 661: log_info(name, seconds, info) 662: result 663: else 664: log_info(name, 0, info) 665: nil 666: end 667: rescue Exception 668: log_info("#{name}: FAILED", 0, 669: (info || {}).merge(:error => $!.class.name, 670: :error_message => $!.message)) 671: raise 672: end
# File lib/active_ldap/adapter/base.rb, line 288 288: def need_credential_sasl_mechanism?(mechanism) 289: not %(GSSAPI EXTERNAL ANONYMOUS).include?(mechanism) 290: end
# File lib/active_ldap/adapter/base.rb, line 414 414: def normalize_array_filter(filter, operator=nil) 415: filter_operator, *components = filter 416: if filter_logical_operator?(filter_operator) 417: operator = filter_operator 418: else 419: components.unshift(filter_operator) 420: components = [components] unless filter_operator.is_a?(Array) 421: end 422: [operator, components] 423: end
# File lib/active_ldap/adapter/base.rb, line 544 544: def normalize_filter_logical_operator(operator) 545: assert_filter_logical_operator(operator) 546: case (operator || :and) 547: when :and, :& 548: :and 549: when :or, :| 550: :or 551: else 552: :not 553: end 554: end
# File lib/active_ldap/adapter/base.rb, line 266 266: def operation(options) 267: retried = false 268: options = options.dup 269: options[:try_reconnect] = true unless options.has_key?(:try_reconnect) 270: try_reconnect = false 271: begin 272: reconnect_if_need(options) 273: try_reconnect = options[:try_reconnect] 274: with_timeout(try_reconnect, options) do 275: yield 276: end 277: rescue ConnectionError 278: if try_reconnect and !retried 279: retried = true 280: @disconnected = true 281: retry 282: else 283: raise 284: end 285: end 286: end
# File lib/active_ldap/adapter/base.rb, line 381 381: def parse_filter(filter, operator=nil) 382: return nil if filter.nil? 383: if !filter.is_a?(String) and !filter.respond_to?(:collect) 384: filter = filter.to_s 385: end 386: 387: case filter 388: when String 389: parse_filter_string(filter) 390: when Hash 391: components = filter.sort_by {|k, v| k.to_s}.collect do |key, value| 392: construct_component(key, value, operator) 393: end 394: construct_filter(components, operator) 395: else 396: operator, components = normalize_array_filter(filter, operator) 397: components = construct_components(components, operator) 398: construct_filter(components, operator) 399: end 400: end
# File lib/active_ldap/adapter/base.rb, line 402 402: def parse_filter_string(filter) 403: if /\A\s*\z/.match(filter) 404: nil 405: else 406: if filter[0, 1] == "(" 407: filter 408: else 409: "(#{filter})" 410: end 411: end 412: end
# File lib/active_ldap/adapter/base.rb, line 292 292: def password(bind_dn, options={}) 293: passwd = options[:password] || @password 294: return passwd if passwd 295: 296: password_block = options[:password_block] || @password_block 297: # TODO: Give a warning to reconnect users with password clearing 298: # Get the passphrase for the first time, or anew if we aren't storing 299: if password_block.respond_to?(:call) 300: passwd = password_block.call(bind_dn) 301: else 302: @logger.error {_('password_block not nil or Proc object. Ignoring.')} 303: return nil 304: end 305: 306: # Store the password for quick reference later 307: if options.has_key?(:store_password) 308: store_password = options[:store_password] 309: else 310: store_password = @store_password 311: end 312: @password = store_password ? passwd : nil 313: 314: passwd 315: end
# File lib/active_ldap/adapter/base.rb, line 263 263: def prepare_connection(options) 264: end
Attempts to reconnect up to the number of times allowed If forced, try once then fail with ConnectionError if not connected.
# File lib/active_ldap/adapter/base.rb, line 567 567: def reconnect(options={}) 568: options = options.dup 569: force = options[:force] 570: retry_limit = options[:retry_limit] || @retry_limit 571: retry_wait = options[:retry_wait] || @retry_wait 572: options[:reconnect_attempts] ||= 0 573: 574: loop do 575: @logger.debug {_('Attempting to reconnect')} 576: disconnect! 577: 578: # Reset the attempts if this was forced. 579: options[:reconnect_attempts] = 0 if force 580: options[:reconnect_attempts] += 1 if retry_limit >= 0 581: begin 582: connect(options) 583: break 584: rescue AuthenticationError 585: raise 586: rescue => detail 587: @logger.error do 588: _("Reconnect to server failed: %s\n" "Reconnect to server failed backtrace:\n" "%s") % [detail.exception, detail.backtrace.join("\n")] 589: end 590: # Do not loop if forced 591: raise ConnectionError, detail.message if force 592: end 593: 594: unless can_reconnect?(options) 595: raise ConnectionError, 596: _('Giving up trying to reconnect to LDAP server.') 597: end 598: 599: # Sleep before looping 600: sleep retry_wait 601: end 602: 603: true 604: end
# File lib/active_ldap/adapter/base.rb, line 608 608: def reconnect_if_need(options={}) 609: return if connecting? 610: with_timeout(false, options) do 611: reconnect(options) 612: end 613: end
# File lib/active_ldap/adapter/base.rb, line 634 634: def root_dse(attrs, options={}) 635: search(:base => "", 636: :scope => :base, 637: :attributes => attrs).collect do |dn, attributes| 638: attributes 639: end 640: end
# File lib/active_ldap/adapter/base.rb, line 624 624: def root_dse_values(key, options={}) 625: dse = root_dse([key], options)[0] 626: return [] if dse.nil? 627: normalized_key = key.downcase 628: dse.each do |_key, _value| 629: return _value if _key.downcase == normalized_key 630: end 631: [] 632: end
# File lib/active_ldap/adapter/base.rb, line 336 336: def sasl_bind(bind_dn, options={}) 337: # Get all SASL mechanisms 338: mechanisms = operation(options) do 339: root_dse_values("supportedSASLMechanisms") 340: end 341: 342: if options.has_key?(:sasl_quiet) 343: sasl_quiet = options[:sasl_quiet] 344: else 345: sasl_quiet = @sasl_quiet 346: end 347: 348: sasl_mechanisms = options[:sasl_mechanisms] || @sasl_mechanisms 349: sasl_mechanisms.each do |mechanism| 350: next unless mechanisms.include?(mechanism) 351: return true if yield(bind_dn, mechanism, sasl_quiet) 352: end 353: false 354: end
# File lib/active_ldap/adapter/base.rb, line 356 356: def simple_bind(bind_dn, options={}) 357: return false unless bind_dn 358: 359: passwd = password(bind_dn, options) 360: return false unless passwd 361: 362: if passwd.empty? 363: if options[:allow_anonymous] 364: @logger.info {_("Skip simple bind with empty password.")} 365: return false 366: else 367: raise AuthenticationError, 368: _("Can't use empty password for simple bind.") 369: end 370: end 371: 372: begin 373: yield(bind_dn, passwd) 374: rescue LdapError::InvalidDnSyntax 375: raise DistinguishedNameInvalid.new(bind_dn) 376: rescue LdapError::InvalidCredentials 377: false 378: end 379: end
# File lib/active_ldap/adapter/base.rb, line 647 647: def target 648: return nil if @uri.nil? 649: if @with_start_tls 650: "#{@uri}(StartTLS)" 651: else 652: @uri 653: end 654: end
# File lib/active_ldap/adapter/base.rb, line 317 317: def with_timeout(try_reconnect=true, options={}, &block) 318: n_retries = 0 319: retry_limit = options[:retry_limit] || @retry_limit 320: begin 321: Timeout.alarm(@timeout, &block) 322: rescue Timeout::Error => e 323: @logger.error {_('Requested action timed out.')} 324: if @retry_on_timeout and retry_limit < 0 and n_retries <= retry_limit 325: if connecting? 326: retry 327: elsif try_reconnect 328: retry if with_timeout(false, options) {reconnect(options)} 329: end 330: end 331: @logger.error {e.message} 332: raise TimeoutError, e.message 333: end 334: end
Disabled; run with --debug to generate this.
Generated with the Darkfish Rdoc Generator 1.1.6.