ruby-ldap / ruby-net-ldap

Pure Ruby LDAP library
https://rubygems.org/gems/net-ldap
Other
400 stars 254 forks source link

ignore bind error in use_connection #375

Open HynekPetrak opened 4 years ago

HynekPetrak commented 4 years ago

In situation when OpenLDAP is configured with "disallow bind_anon" in slapd.conf, the bind operation will return "LDAP_INAPPROPRIATE_AUTH - anonymous bind disallowed". According to https://www.openldap.org/doc/admin23/security.html#Authentication%20Methods a anonymous bind is not fatal for an LDAP server and server will still respond to search or other operations, according to ACLs. Quoting: "Note that disabling the anonymous bind mechanism does not prevent anonymous access to the directory."

Can you remove the line return result unless result.result_code == Net::LDAP::ResultCodeSuccess from use_connection method? https://github.com/ruby-ldap/ruby-net-ldap/blob/master/lib/net/ldap.rb#L1310

To be able to perform search and other operation even after bind has failed?

HarlemSquirrel commented 4 years ago

Interesting. We'll have to see if we can reproduce this with an OpenLDAP container.

HarlemSquirrel commented 4 years ago

I was able to get this response doing the following

# Run an OpenLDAP container in a separate terminal
scripts/ldap-docker

# Make a successful anonymous bind and search
ldapsearch -x -H ldap://localhost -b '' -s base namingContexts

# Change the configuration to disallow anonymous bind
ldapmodify -x -H ldap://localhost -D 'cn=admin,cn=config' -w 'config' <<+
dn: cn=config
changetype: modify
replace: olcDisallows
olcDisallows: bind_anon
+

# Make an unsuccessful bind and search
ldapsearch -x -H ldap://localhost -b '' -s base namingContexts
# ldap_bind: Inappropriate authentication (48)
#         additional info: anonymous bind disallowed

We see that when the anonymous bind fails, we do not get a successful search result back using ldapsearch.

HarlemSquirrel commented 4 years ago

This reproduces the issue as well

require_relative 'lib/net-ldap'

@ldap = Net::LDAP.new host: 'localhost',
                     port: 389,
                     auth: { method: :anonymous }

@ldap_config = Net::LDAP.new host: 'localhost',
                            port: 389,
                            auth: { 
                              method: :simple,
                              username: 'cn=admin,cn=config',
                              password: 'config'
                            }

def print_naming_contexts
  puts "\nSearching anonymously"
  puts @ldap.search(base: '', scope: Net::LDAP::SearchScope_BaseObject, attributes: %w[namingContexts])
           .map(&:to_ldif)
  puts @ldap.get_operation_result.message
end

puts "\nEnabling anonymous bind"
@ldap_config.modify dn: 'cn=config', 
                   operations: [
                     [:delete, 'olcDisallows']
                   ]
puts @ldap_config.get_operation_result.message

print_naming_contexts

puts "\nDisabling anonymous bind"
@ldap_config.modify dn: 'cn=config', 
                   operations: [
                     [:replace, 'olcDisallows', ['bind_anon']]
                   ]
puts @ldap_config.get_operation_result.message

print_naming_contexts
HarlemSquirrel commented 4 years ago

I'm thinking we'll want to indicate somehow that the bind failed but the search succeeded. Perhaps print a warning?

# Yields an open connection if there is one, otherwise establishes a new
  # connection, binds, and yields it. If binding fails, it will return the
  # result from that, and :use_connection: will not yield at all. If not
  # the return value is whatever is returned from the block.
  def use_connection(args)
    if @open_connection
      yield @open_connection
    else
      begin
        conn = new_connection
        auth = args[:auth] || @auth
        result = conn.bind(auth)

        unless [Net::LDAP::ResultCodeSuccess, 
                Net::LDAP::ResultCodeInappropriateAuthentication].include?(result.result_code)
          return result
        end

        if result.result_code == Net::LDAP::ResultCodeInappropriateAuthentication
          warn "Inappropriate authentication occurred with #{auth[:method]} auth."
        end

        yield conn
      ensure
        conn.close if conn
      end
    end
  end
HynekPetrak commented 4 years ago

Ldapsearch perhaps does not print a search result when an anonymous bind fails, however the server returns the result. Tested when you run the search within a #open |ldap| block

HarlemSquirrel commented 4 years ago

We should also test this with another LDAP server such as OpenDJ to see what would happen there.