Authenticating against active directory using python + ldap

PythonAuthenticationActive DirectoryLdap

Python Problem Overview


How do I authenticate against AD using Python + LDAP. I'm currently using the python-ldap library and all it is producing is tears.

I can't even bind to perform a simple query:

import sys
import ldap


Server = "ldap://my-ldap-server"
DN, Secret, un = sys.argv[1:4]
    
Base = "dc=mydomain,dc=co,dc=uk"
Scope = ldap.SCOPE_SUBTREE
Filter = "(&(objectClass=user)(sAMAccountName="+un+"))"
Attrs = ["displayName"]

l = ldap.initialize(Server)
l.protocol_version = 3
print l.simple_bind_s(DN, Secret)

r = l.search(Base, Scope, Filter, Attrs)
Type,user = l.result(r,60)
Name,Attrs = user[0]
if hasattr(Attrs, 'has_key') and Attrs.has_key('displayName'):
  displayName = Attrs['displayName'][0]
  print displayName

sys.exit()

Running this with [email protected] password username gives me one of two errors:

Invalid Credentials - When I mistype or intentionally use wrong credentials it fails to authenticate.

>ldap.INVALID_CREDENTIALS: {'info': '80090308: LdapErr: DSID-0C090334, comment: AcceptSecurityContext error, data 52e, vece', 'desc': 'Invalid credentials'}

Or

>ldap.OPERATIONS_ERROR: {'info': '00000000: LdapErr: DSID-0C090627, comment: In order to perform this operation a successful bind must be completed on the connection., data 0, vece', 'desc': 'Operations error'}

What am I missing out to bind properly?

I am getting the same errors on fedora and windows.

Python Solutions


Solution 1 - Python

I was missing

l.set_option(ldap.OPT_REFERRALS, 0)

From the init.

Solution 2 - Python

If you are open to using pywin32, you can use Win32 calls from Python. This is what we do in our CherryPy web server:

import win32security
token = win32security.LogonUser(
    username,
    domain,
    password,
    win32security.LOGON32_LOGON_NETWORK,
    win32security.LOGON32_PROVIDER_DEFAULT)
authenticated = bool(token)

Solution 3 - Python

That worked for me, l.set_option(ldap.OPT_REFERRALS, 0) was the key to access the ActiveDirectory. Moreover, I think that you should add an "con.unbind()" in order to close the connection before finishing the script.

Solution 4 - Python

Here's some simple code that works for me.

import ldap  # run 'pip install python-ldap' to install ldap module.
conn = ldap.open("ldaphost.company.com")
conn.simple_bind_s("[email protected]", "mypassword")

This is based on a previous answer.

Solution 5 - Python

if you have Kerberos installed and talking to AD, as would be the case with, say, Centrify Express installed and running, you might just use python-kerberos. E.g.

import kerberos
kerberos.checkPassword('joe','pizza','krbtgt/x.pizza.com','X.PIZZA.COM')`

would return True a user 'joe' has password 'pizza' in the Kerberos realm X.PIZZA.COM. (typically, I think, the latter would be the same as the name of the AD Domain)

Solution 6 - Python

I see your comment to @Johan Buret about the DN not fixing your problem, but I also believe that is what you should look into.

Given your example, the DN for the default administrator account in AD will be: cn=Administrator,cn=Users,dc=mydomain,dc=co,dc=uk - please try that.

Solution 7 - Python

Based on the excellent ldap3 tutorial:

>>> from ldap3 import Server, Connection, ALL, NTLM
>>> server = Server('server_name_or_ip', get_info=ALL)
>>> conn = Connection(server, user="user_name", password="password", auto_bind=True)
>>> conn.extend.standard.who_am_i()
>>> server.info

I did the above in Python3 but it's supposed to be compatible with Python 2.

Solution 8 - Python

I tried to add

> l.set_option(ldap.OPT_REFERRALS, 0)

but instead of an error Python just hangs and won't respond to anything any more. Maybe I'm building the search query wrong, what is the Base part of the search? I'm using the same as the DN for the simple bind (oh, and I had to do l.simple_bind, instead of l.simple_bind_s):

import ldap
local = ldap.initialize("ldap://127.0.0.1")
local.simple_bind("CN=staff,DC=mydomain,DC=com")
#my pc is not actually connected to this domain 
result_id = local.search("CN=staff,DC=mydomain,DC=com", ldap.SCOPE_SUBTREE, "cn=foobar", None)
local.set_option(ldap.OPT_REFERRALS, 0)
result_type, result_data = local.result(result_id, 0)

I'm using AD LDS and the instance is registered for the current account.

Solution 9 - Python

I had the same issue, but it was regarding the password encoding

.encode('iso-8859-1')

Solved the problem.

Solution 10 - Python

Use a Distinguished Name to log on your system."CN=Your user,CN=Users,DC=b2t,DC=local" It should work on any LDAP system, including AD

Solution 11 - Python

For me changing from simple_bind_s() to bind() did the trick.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Question1729View Question on Stackoverflow
Solution 1 - Python1729View Answer on Stackoverflow
Solution 2 - PythondavidavrView Answer on Stackoverflow
Solution 3 - PythonalfredocamberaView Answer on Stackoverflow
Solution 4 - PythonJohnMuddView Answer on Stackoverflow
Solution 5 - PythonDima PasechnikView Answer on Stackoverflow
Solution 6 - PythonDaniel BungertView Answer on Stackoverflow
Solution 7 - PythonNagevView Answer on Stackoverflow
Solution 8 - PythonlanoxxView Answer on Stackoverflow
Solution 9 - PythonDr.ÜView Answer on Stackoverflow
Solution 10 - PythonJohan BuretView Answer on Stackoverflow
Solution 11 - PythonxclView Answer on Stackoverflow