Authenticating against active directory using python + ldap
Asked Answered
O

12

100

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.

Overpowering answered 26/9, 2008 at 16:8 Comment(1)
"...and all it is producing is tears." Does tears rhyme with Bears or Beers?Taveras
O
52

I was missing

l.set_option(ldap.OPT_REFERRALS, 0)

From the init.

Overpowering answered 26/9, 2008 at 16:18 Comment(3)
The root cause of this bug is that you have referrals in the initial response and the windows LDAP code does not send the credentials to the referral server. If you used kerberos credentials it should work.Trapeziform
I had different symptoms but this same option fixed my problem. Summarized it in a blog post: chaverma.com/blog/index.php/2013/06/…Wellknit
Not sure if related, but I had the same problem and it seems 1729's solution did something - But sometimes the LDAP server just answers INVALID CREDENTIALS immediately. After a while it calms down and works again.Slave
P
35

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)
Primitivism answered 26/9, 2008 at 20:23 Comment(2)
This solution worked for me in a Python Flask application while behind a restrictive NTLM corporate proxy. Some other LDAP-based options simply wouldn't work.Escudo
@Escudo I had similar issues, after debugging for 4 hours I finally found this threadTroublemaker
P
7

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.

Perorate answered 14/7, 2009 at 16:2 Comment(2)
From the python-ldap documentation: Instances of LDAPObject are returned by initialize(). The connection is automatically unbound and closed when the LDAP object is deleted.Dividivi
You close the session, not the connection.Hispanic
M
6

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.

Maite answered 16/8, 2013 at 21:32 Comment(1)
This doesn't work anymore, you'll receive AttributeError: module 'ldap' has no attribute 'open'Methylal
P
4

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.

Peristyle answered 29/1, 2019 at 8:22 Comment(0)
V
3

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)

Viper answered 1/8, 2011 at 18:46 Comment(0)
S
2

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.

Sorrento answered 30/9, 2008 at 14:36 Comment(0)
H
1

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.

Haddington answered 13/10, 2010 at 4:11 Comment(0)
E
1

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

.encode('iso-8859-1')

Solved the problem.

Elspet answered 13/7, 2016 at 10:1 Comment(0)
M
0

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

Martymartyn answered 26/9, 2008 at 17:14 Comment(0)
C
0

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

Cloister answered 30/3, 2012 at 13:25 Comment(0)
S
0

Implementing LDAP with python is easier with ldap3. I have used it couple of times and seems pretty easier and secure. Official documentation is easier to understand and follow. https://ldap3.readthedocs.io/en/latest/

Sforza answered 28/2, 2024 at 3:55 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.