Search code examples
pythonactive-directoryldapldap-query

Python LDAP: LDAPObject.search_s() works, but LDAPObject.search() doesn't


I am trying to implement a basic LDAP authentication script in Python, and I am trying to just perform a simple LDAP search and see if it works. I believe I have correctly created and set up my LDAP object and connection.

After binding, I try to perform a search. Using the LDAPObject.search_s() method successfully returns a list of strings with user information. When I use the LDAPObject.search() method, though, the method returns result code 2, which is a protocol error. The reason I want to use the search() method is because it returns an int and not a list. From what I understand according to the Python LDAP documentation, the two methods can take in the same arguments, so I don't understand why one method is returning an error and not the other.

Here is my code:

import ldap
import getpass

# get login info

username = raw_input("Enter your username: ")
password = getpass.getpass("Enter your password: ")

ldap_server = "LDAP://ipaddress:port"
base_dn = "OU=Domain Users,DC=dummyname,DC=com"
user_dn = username + "@dummyname.com"
search_filter = "(&(objectClass=user)(sAMAccountName=" + username + "))"

ld = ldap.initialize(ldap_server);
ld = ldap.open(ldap_server)
ld.protocol_version = 3
ld.set_option(ldap.OPT_REFERRALS, 0)

# bind user information to ldap connection

try:
    print ld.simple_bind_s(user_dn, password)
    results = ld.search(base_dn, ldap.SCOPE_SUBTREE, search_filter)
    print results
    ld.unbind_s()
except ldap.INVALID_CREDENTIALS:
    print "Your username or password is invalid."
except Exception as e:
    print("Connection unsuccessful: " + str(e.message))
    ld.unbind_s()

Full output of this code is:

Enter your username: myusername
Enter your password:
(97, [], 1, [])
2

Any help would be greatly appreciated. Thanks.


Solution

  • The following command is using an async search which does not block to wait for a return value. The int it returns is actually the MSGID of the LDAPObject which you need to get the return value when it is returned.

    msgid = ld.search(base_dn, ldap.SCOPE_SUBTREE, search_filter)  # Returns int of msgid without blocking
    

    To get the actual results you need to call

    actual_results = ld.result(msgid)   # Blocks until search is done and returns [(dn,attrs)]
    

    Using the following commands causes the LDAPObject to search in "sequential order" thus blocking the program.

    results = ld.search_s(base_dn, ldap.SCOPE_SUBTREE, search_filter)  # blocks until all results are received   [(dn,attrs)]