# class ActiveLdap::Adapter::NetLdap

### Constants

CHARS
METHOD

### Public Instance Methods

add(dn, entries, options={}) click to toggle source
Calls superclass method ActiveLdap::Adapter::Base#add

    # File lib/active_ldap/adapter/net_ldap.rb, line 105
    def add(dn, entries, options={})
      super do |_dn, _entries|
        attributes = {}
        _entries.each do |type, key, attrs|
          attrs.each do |name, values|
            attributes[name] = values
          end
        end
        args = {:dn => _dn, :attributes => attributes}
        info = args.dup
        execute(:add, info, args)
      end
    end

bind(options={}) click to toggle source
Calls superclass method ActiveLdap::Adapter::Base#bind

    # File lib/active_ldap/adapter/net_ldap.rb, line 50
    def bind(options={})
      begin
        super
      rescue Net::LDAP::LdapError
        raise AuthenticationError, $!.message
      end
    end

bind_as_anonymous(options={}) click to toggle source
Calls superclass method ActiveLdap::Adapter::Base#bind_as_anonymous

    # File lib/active_ldap/adapter/net_ldap.rb, line 58
    def bind_as_anonymous(options={})
      super do
        execute(:bind, {:name => "bind: anonymous"}, {:method => :anonymous})
        true
      end
    end

connect(options={}) click to toggle source
Calls superclass method ActiveLdap::Adapter::Base#connect

    # File lib/active_ldap/adapter/net_ldap.rb, line 23
    def connect(options={})
      super do |host, port, method|
        config = {
          :host => host,
          :port => port,
        }
        config[:encryption] = {:method => method} if method
        begin
          uri = construct_uri(host, port, method == :simple_tls)
          with_start_tls = method == :start_tls
          info = {:uri => uri, :with_start_tls => with_start_tls}
          [log("connect", info) {Net::LDAP::Connection.new(config)},
           uri, with_start_tls]
        rescue Net::LDAP::LdapError
          raise ConnectionError, $!.message
        end
      end
    end

delete(targets, options={}) click to toggle source
Calls superclass method ActiveLdap::Adapter::Base#delete

    # File lib/active_ldap/adapter/net_ldap.rb, line 97
    def delete(targets, options={})
      super do |target|
        args = {:dn => target}
        info = args.dup
        execute(:delete, info, args)
      end
    end

modify(dn, entries, options={}) click to toggle source
Calls superclass method ActiveLdap::Adapter::Base#modify

    # File lib/active_ldap/adapter/net_ldap.rb, line 119
    def modify(dn, entries, options={})
      super do |_dn, _entries|
        info = {:dn => _dn, :attributes => _entries}
        execute(:modify, info,
                :dn => _dn,
                :operations => parse_entries(_entries))
      end
    end

modify_rdn(dn, new_rdn, delete_old_rdn, new_superior, options={}) click to toggle source
Calls superclass method ActiveLdap::Adapter::Base#modify_rdn

    # File lib/active_ldap/adapter/net_ldap.rb, line 128
    def modify_rdn(dn, new_rdn, delete_old_rdn, new_superior, options={})
      super do |_dn, _new_rdn, _delete_old_rdn, _new_superior|
        info = {
          :name => "modify: RDN",
          :dn => _dn,
          :new_rdn => _new_rdn,
          :new_superior => _new_superior,
          :delete_old_rdn => _delete_old_rdn
        }
        execute(:rename, info,
                :olddn => _dn,
                :newrdn => _new_rdn,
                :delete_attributes => _delete_old_rdn,
                :new_superior => _new_superior)
      end
    end

search(options={}) { |dn, attributes| ... } click to toggle source
Calls superclass method ActiveLdap::Adapter::Base#search

    # File lib/active_ldap/adapter/net_ldap.rb, line 65
    def search(options={})
      use_paged_results = options[:use_paged_results]
      if use_paged_results or use_paged_results.nil?
        paged_results_supported = supported_control.paged_results?
      else
        paged_results_supported = false
      end
      super(options) do |base, scope, filter, attrs, limit|
        args = {
          :base => base,
          :scope => scope,
          :filter => filter,
          :attributes => attrs,
          :size => limit,
          :paged_searches_supported => paged_results_supported,
        }
        info = {
          :base => base, :scope => scope_name(scope),
          :filter => filter, :attributes => attrs, :limit => limit,
          :paged_results_supported => paged_results_supported,
        }
        execute(:search, info, args) do |entry|
          attributes = {}
          entry.original_attribute_names.each do |name|
            value = entry[name]
            attributes[name] = value if value
          end
          yield([entry.dn, attributes])
        end
      end
    end

unbind(options={}) click to toggle source
Calls superclass method ActiveLdap::Adapter::Base#unbind

    # File lib/active_ldap/adapter/net_ldap.rb, line 42
    def unbind(options={})
      super do
        log("unbind") do
          @connection.close # Net::LDAP doesn't implement unbind.
        end
      end
    end

### Private Instance Methods

ensure_method(method) click to toggle source

    # File lib/active_ldap/adapter/net_ldap.rb, line 173
    def ensure_method(method)
      method ||= "plain"
      normalized_method = method.to_s.downcase.to_sym
      return METHOD[normalized_method] if METHOD.has_key?(normalized_method)

      available_methods = METHOD.keys.collect {|m| m.inspect}.join(", ")
      format = _("%s is not one of the available connect methods: %s")
      raise ConfigurationError, format % [method.inspect, available_methods]
    end

ensure_mod_type(type) click to toggle source

    # File lib/active_ldap/adapter/net_ldap.rb, line 309
    def ensure_mod_type(type)
      case type
      when :replace, :add, :delete
        type
      else
        raise ArgumentError, _("unknown type: %s") % type
      end
    end

ensure_scope(scope) click to toggle source

    # File lib/active_ldap/adapter/net_ldap.rb, line 183
    def ensure_scope(scope)
      scope_map = {
        :base => Net::LDAP::SearchScope_BaseObject,
        :sub => Net::LDAP::SearchScope_WholeSubtree,
        :one => Net::LDAP::SearchScope_SingleLevel,
      }
      value = scope_map[scope || :sub]
      if value.nil?
        available_scopes = scope_map.keys.inspect
        format = _("%s is not one of the available LDAP scope: %s")
        raise ArgumentError, format % [scope.inspect, available_scopes]
      end
      value
    end

execute(method, info=nil, *args, &block) click to toggle source

    # File lib/active_ldap/adapter/net_ldap.rb, line 146
    def execute(method, info=nil, *args, &block)
      name = (info || {}).delete(:name) || method
      result = log(name, info) do
        begin
          @connection.send(method, *args, &block)
        rescue Errno::EPIPE, Errno::ECONNRESET
          raise ConnectionError, "#{$!.class}: #{$!.message}"
        end
      end
      message = nil
      case result
      when Hash
        message = result[:errorMessage]
        result = result[:resultCode]
      when Net::LDAP::PDU
        message = result.error_message
        result = result.result_code
      end
      unless result.zero?
        klass = LdapError::ERRORS[result]
        klass ||= LdapError
        return if klass == LdapError::SizeLimitExceeded
        message = [Net::LDAP.result2string(result), message].compact.join(": ")
        raise klass, message
      end
    end

generate_client_nonce(size=32) click to toggle source

    # File lib/active_ldap/adapter/net_ldap.rb, line 278
    def generate_client_nonce(size=32)
      nonce = ""
      size.times do |i|
        nonce << CHARS[rand(CHARS.size)]
      end
      nonce
    end

parse_entries(entries) click to toggle source

    # File lib/active_ldap/adapter/net_ldap.rb, line 298
    def parse_entries(entries)
      result = []
      entries.each do |type, key, attributes|
        mod_type = ensure_mod_type(type)
        attributes.each do |name, values|
          result << [mod_type, name, values]
        end
      end
      result
    end

parse_sasl_digest_md5_credential(cred) click to toggle source

    # File lib/active_ldap/adapter/net_ldap.rb, line 269
    def parse_sasl_digest_md5_credential(cred)
      params = {}
      cred.scan(/(\w+)=(\"?)(.+?)\2(?:,|$)/) do |name, sep, value|
        params[name] = value
      end
      params
    end

sasl_bind(bind_dn, options={}) click to toggle source
Calls superclass method ActiveLdap::Adapter::Base#sasl_bind

    # File lib/active_ldap/adapter/net_ldap.rb, line 206
    def sasl_bind(bind_dn, options={})
      super do |_bind_dn, mechanism, quiet|
        normalized_mechanism = mechanism.downcase.gsub(/-/, '_')
        sasl_bind_setup = "sasl_bind_setup_#{normalized_mechanism}"
        next unless respond_to?(sasl_bind_setup, true)
        initial_credential, challenge_response =
          send(sasl_bind_setup, _bind_dn, options)
        args = {
          :method => :sasl,
          :initial_credential => initial_credential,
          :mechanism => mechanism,
          :challenge_response => challenge_response,
        }
        info = {
          :name => "bind: SASL", :dn => _bind_dn, :mechanism => mechanism,
        }
        execute(:bind, info, args)
        true
      end
    end

sasl_bind_setup_digest_md5(bind_dn, options) click to toggle source

    # File lib/active_ldap/adapter/net_ldap.rb, line 227
    def sasl_bind_setup_digest_md5(bind_dn, options)
      initial_credential = ""
      nonce_count = 1
      challenge_response = Proc.new do |cred|
        params = parse_sasl_digest_md5_credential(cred)
        qops = params["qop"].split(/,/)
        unless qops.include?("auth")
          raise ActiveLdap::AuthenticationError,
                _("unsupported qops: %s") % qops.inspect
        end
        qop = "auth"
        server = @connection.instance_variable_get("@conn").addr[2]
        realm = params['realm']
        uri = "ldap/#{server}"
        nc = "%08x" % nonce_count
        nonce = params["nonce"]
        cnonce = generate_client_nonce
        requests = {
          :username => bind_dn.inspect,
          :realm => realm.inspect,
          :nonce => nonce.inspect,
          :cnonce => cnonce.inspect,
          :nc => nc,
          :qop => qop,
          :maxbuf => "65536",
          "digest-uri" => uri.inspect,
        }
        a1 = "#{bind_dn}:#{realm}:#{password(cred, options)}"
        a1 = "#{Digest::MD5.digest(a1)}:#{nonce}:#{cnonce}"
        ha1 = Digest::MD5.hexdigest(a1)
        a2 = "AUTHENTICATE:#{uri}"
        ha2 = Digest::MD5.hexdigest(a2)
        response = "#{ha1}:#{nonce}:#{nc}:#{cnonce}:#{qop}:#{ha2}"
        requests["response"] = Digest::MD5.hexdigest(response)
        nonce_count += 1
        requests.collect do |key, value|
          "#{key}=#{value}"
        end.join(",")
      end
      [initial_credential, challenge_response]
    end

scope_name(scope) click to toggle source

    # File lib/active_ldap/adapter/net_ldap.rb, line 198
    def scope_name(scope)
      {
        Net::LDAP::SearchScope_BaseObject => :base,
        Net::LDAP::SearchScope_WholeSubtree => :sub,
        Net::LDAP::SearchScope_SingleLevel => :one,
      }[scope]
    end

simple_bind(bind_dn, options={}) click to toggle source
Calls superclass method ActiveLdap::Adapter::Base#simple_bind

    # File lib/active_ldap/adapter/net_ldap.rb, line 286
    def simple_bind(bind_dn, options={})
      super do |_bind_dn, password|
        args = {
          :method => :simple,
          :username => _bind_dn,
          :password => password,
        }
        execute(:bind, {:dn => _bind_dn}, args)
        true
      end
    end