使用 python + ldap 对活动目录进行身份验证

如何使用 Python + LDAP 对 AD 进行身份验证。我目前正在使用 python-ldap 库,它所产生的只是眼泪。

我甚至不能绑定执行一个简单的查询:

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()

myusername@mydomain.co.uk password username运行这个程序会出现两个错误之一:

Invalid Credentials-当我输入错误或故意使用错误的凭据时,它无法进行身份验证。

INVALID _ CREDENTIALS: {‘ info’: ‘80090308: LdapErr: DSID-0C090334,注释: AcceptSecurityContext error,data 52e,vece’,‘ desc’: ‘ Invalid凭证’}

或者

OPERATION _ ERROR: {‘ info’: ‘00000000: LdapErr: DSID-0C090627,comments: 为了执行这个操作,必须在连接上完成一个成功的绑定. ,data 0,vece’,‘ desc’: ‘ Operations error’}

为了正确绑定,我错过了什么?

我在软呢帽和窗户上得到了相同的错误。

101412 次浏览

I was missing

l.set_option(ldap.OPT_REFERRALS, 0)

From the init.

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

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)

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.

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.

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.

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)

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

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("myuser@company.com", "mypassword")

This is based on a previous answer.

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

.encode('iso-8859-1')

Solved the problem.

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.