使用Python + LDAP身份验证活动目录

100

我该如何使用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后,我遇到了以下两种错误之一:

无效的凭据 - 当我输入错误的凭据或者故意使用错误的凭据时,认证失败。

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

或者

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'}

我错过了什么步骤来正确绑定?

我在fedora和windows上遇到了相同的错误。


4
"…and all it is producing is tears."中的"tears"发音与"Beers"押韵。 - philshem
11个回答

52

我错过了

l.set_option(ldap.OPT_REFERRALS, 0)

从 init 开始。


3
这个错误的根本原因是初始响应中有引荐,并且 Windows LDAP 代码没有将凭据发送到引荐服务器。如果你使用了 Kerberos 凭据,它应该可以工作。 - schlenk
2
我曾经遇到不同的症状,但是同样的选项解决了我的问题。我在博客文章中总结了这个过程:http://www.chaverma.com/blog/index.php/2013/06/python-ldap-functions-run-forever-against-activedirectory/ - Chris
不确定是否相关,但我遇到了同样的问题,而且似乎1729的解决方案起了作用 - 但有时LDAP服务器会立即返回INVALID CREDENTIALS错误。过一段时间后就会恢复正常工作。 - Nitay

34

如果您愿意使用pywin32,您可以从Python中使用Win32调用。这就是我们在CherryPy Web服务器中所做的:

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

4
我会尽力做到简明扼要,清晰易懂地翻译内容,并确保不改变原意。以下是需要翻译的内容:简洁明了!谢谢! - alexroat
1
这个解决方案在我使用 Python Flask 应用程序时,在受限制的 NTLM 公司代理后面运行良好。其他一些基于 LDAP 的选项根本无法工作。 - Gigaflop
@Gigaflop 我也遇到了类似的问题,调试了4个小时后,我终于找到了这个帖子。 - McSebi

7

这对我很有用,l.set_option(ldap.OPT_REFERRALS, 0)是访问ActiveDirectory的关键。此外,我认为你应该在脚本结束之前添加一个"con.unbind()"来关闭连接。


8
LDAPObject的实例是由initialize()返回的。当LDAP对象被删除时,连接会自动解除绑定和关闭。 - Søren Løvborg
你关闭的是会话,而不是连接。 - Romulus

6
这是一些对我有效的简单代码。
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")

这是基于一个之前的答案

1
这个不再起作用了,你会收到 AttributeError: module 'ldap' has no attribute 'open' - Josh Correia

4
基于优秀的ldap3教程
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

我用Python3完成了上述工作,但它应该与Python 2兼容。

3

如果您已经安装了Kerberos并与AD通信,例如已安装并运行Centrify Express,则可以使用python-kerberos。例如:

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

如果在Kerberos领域X.PIZZA.COM中,用户'joe'的密码为'pizza',则会返回True。(通常情况下,我认为后者与AD域的名称相同)

2

我看到你在评论@Johan Buret时提到了DN没有解决你的问题,但我认为这是你应该研究的方向。

以你的例子而言,在AD中默认管理员帐户的DN如下: cn=Administrator,cn=Users,dc=mydomain,dc=co,dc=uk - 请尝试使用此方法。


1
我遇到了相同的问题,但是它与密码编码有关。
.encode('iso-8859-1')

解决了问题。

1

我尝试添加

l.set_option(ldap.OPT_REFERRALS, 0)

但是Python没有报错,而是一直挂起并且不再响应任何操作了。也许是我的搜索查询构建不正确,那么搜索的“Base”部分是什么?我正在使用与简单绑定的DN相同的内容(哦,还有我必须使用l.simple_bind而不是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)

我正在使用AD LDS,该实例已为当前帐户注册。


0

使用专有名称登录您的系统。"CN=Your user,CN=Users,DC=b2t,DC=local"它应该适用于任何LDAP系统,包括AD。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接