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


89

如何使用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 -输入错误或故意使用错误的凭据时,它无法通过身份验证。

ldap.INVALID_CREDENTIALS:{'info':'80090308:LdapErr:DSID-0C090334,评论:AcceptSecurityContext错误,数据52e,vece','desc':'无效凭据'}

要么

ldap.OPERATIONS_ERROR:{'info':'00000000:LdapErr:DSID-0C090627,注释:为了执行此操作,必须在连接上完成成功的绑定。,数据0,vece','desc':'操作错误'}

我缺少正确绑定的东西吗?

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


2
“……它所产生的只是眼泪。” 难道眼泪与熊或啤酒韵?
philshem 2014年

Answers:


47

我不见了

l.set_option(ldap.OPT_REFERRALS, 0)

从init开始。


3
此错误的根本原因是,您在初始响应中具有引用,并且Windows LDAP代码没有将凭据发送到引用服务器。如果您使用的是kerberos凭证,那么它应该可以使用。
schlenk

2
我有不同的症状,但此相同选项解决了我的问题。在一篇博客文章中总结吧:chaverma.com/blog/index.php/2013/06/...
克里斯-

不确定是否相关,但是我遇到了同样的问题,似乎1729的解决方案做了一些工作-但有时LDAP服务器只是立即回答INVALID CREDENTIALS。一段时间后,它平静下来并再次起作用。
尼泰(Natay)2014年

28

如果您愿意使用pywin32,则可以使用Python中的Win32调用。这是我们在CherryPy Web服务器中执行的操作:

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

3
简单干净!谢谢!
alexroat 2013年

此解决方案在Python Flask应用程序中对我有效,而在限制性NTLM公司代理后面。其他一些基于LDAP的选项根本行不通。
Gigaflop

7

这对我有用l.set_option(ldap.OPT_REFERRALS,0)是访问ActiveDirectory的关键。此外,我认为您应该在完成脚本之前添加“ con.unbind()”以关闭连接。


8
python-ldap文档中:的实例由LDAPObject返回initialize()。删除LDAP对象时,连接自动解除绑定并关闭。
索伦Løvborg

您关闭会话,而不是连接。
罗慕路斯(Romulus)

5

这是一些对我有用的简单代码。

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'
乔什·科雷亚

3

如果您已经安装了Kerberos并与AD通讯(例如,安装并正在运行Centrify Express的情况),则可能只使用python-kerberos。例如

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

如果用户“ joe”在Kerberos领域X.PIZZA.COM中具有密码“ pizza”,则返回True。(通常,我认为后者将与AD域的名称相同)


2

我看到您对@Johan Buret的评论有关DN无法解决您的问题,但我也认为这是您应该研究的内容。

以您的示例为例,AD中默认管理员帐户的DN为:cn = Administrator,cn = Users,dc = mydomain,dc = co,dc = uk-请尝试这样做。


2

基于出色的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兼容。


1

我尝试添加

l.set_option(ldap.OPT_REFERRALS,0)

但是Python不会挂起错误,而是挂起了,不再响应任何内容。也许我在构建搜索查询时出错,搜索的基础部分是什么?我使用的是与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,并且该实例已为当前帐户注册。


1

我遇到了同样的问题,但它与密码编码有关

.encode('iso-8859-1')

解决了问题。



0

对于我来说,从更改simple_bind_s()bind()成功。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.