与this question类似,我尝试使用python ldap(CentOS 6.2 x86_64,Python 2.6.6,python-ldap 2.3.10)对2003 Active Directory执行简单身份验证。
尽管遵循了init中的所有常规步骤,包括
conn.set_option(ldap.OPT_REFERRALS, 0)
如果我传递了正确的凭据,我总是获得(97, [])
返回:
>>> import ldap
>>> conn = ldap.initialize('ldap://ad.server.domain.com')
>>> conn.protocol_version = 3
>>> conn.set_option(ldap.OPT_REFERRALS, 0)
>>> conn.simple_bind_s('user@domain.com', 'WrongPassword')
ldap.INVALID_CREDENTIALS: {'info': '80090308: LdapErr: DSID-0C090334, comment: AcceptSecurityContext error, data 52e, vece', 'desc': 'Invalid credentials'}
>>> conn.simple_bind_s('user@domain.com', 'CorrectPassword')
(97, [])
错误代码97不成功;它是从AD返回的LDAP_REFERRAL_LIMIT_EXCEEDED
错误。我也不能将它用作事实上的成功指标,因为:
>>> conn.simple_bind_s('', 'CorrectPassword')
(97, [])
>>> conn.simple_bind_s('', '')
(97, [])
更令人沮丧的是,此脚本是使用Net :: LDAP从旧的Perl脚本迁移, 返回0,以便成功通过身份验证绑定到同一个AD和服务器。
我在python-ldap上找到的所有信息表明我正在做的事情应该是Just Work;我倾向于认为AD服务器有问题,但Perl脚本确实在成功绑定时返回正确的LDAP代码。
我在一个旧的CentOS 5.5盒子上测试了python-ldap 2.2.0和python 2.4.4,它以“完全相同的方式”“失败”。
有谁知道我错过了什么?
编辑:每个请求,这里是可行的Perl脚本。 Net::LDAP
从LDAP服务器返回返回码,AD服务器返回0x00,“成功请求”,AFAICT。
#!/usr/bin/perl -w
use strict;
use Net::LDAP;
## Corporate subdomains
my @domains = ("americas", "asia", "europe");
# AD connect timeout
my $timeout = 10;
# Set AD server info.
my $port = "389";
my $host = "server.domain.com";
my $user = shift @ARGV;
chomp $user;
my $password = <STDIN>;
$password =~ s/\r\n//;
chomp $password;
my $ldap = Net::LDAP->new($host, port => $port, timeout => $timeout ) ||
die "Unable to connect to LDAP server";
my $bind_return = 1;
foreach (@domains) {
my $result = $ldap->bind( "$user\@$_.domain.com", password => $password );
if( $result->code == 0) {
$bind_return = 0;
last;
}
}
## Unbind and return
$ldap->unbind;
if ($bind_return) { print "Authentication Failed. Access Denied\n" }
exit $bind_return;
答案 0 :(得分:14)
python-ldap库的作者MichaelStröder因此启发了我:
97不是LDAP结果代码。这是结果类型 ldap.RES_BIND。通常,您不必查看返回的结果 通过LDAPObject.simple_bind_s()(除非你想提取绑定 响应控制)。
如果LDAP结果代码不为0,则引发伴随的异常 比如你的例子中的ldap.INVALID_CREDENTIALS。
所以你的代码应该是这样的:
try:
conn.simple_bind_s('user@domain.com', 'WrongPassword')
except ldap.INVALID_CREDENTIALS:
user_error_msg('wrong password provided')
这些结果的原因:
>>> conn.simple_bind_s('', 'CorrectPassword')
(97, [])
>>> conn.simple_bind_s('', '')
(97, [])
是开箱即用的2003 Active Directory allows anonymous binds。因此,如果唯一正在测试的是simple_bind_s()
是否会抛出错误,那么根本不提供用户ID仍将通过简单的绑定检查。
2003 Active Directory 确实要求对不是rootDSE属性的任何搜索进行身份验证,因此出于内部目的,我们在try:
块中添加了一个简单的搜索:
try:
conn.simple_bind_s('user@domain.com', 'SubmittedPassword')
conn.search_st('DC=domain,DC=com', ldap.SCOPE_SUBTREE, '(objectClass=container)', 'name', 0, 30)
except ldap.INVALID_CREDENTIALS:
user_error_msg('wrong password provided')
答案 1 :(得分:0)
此错误表示您的conn.set_option(ldap.OPT_REFERRALS, 0)
未受影响。
因此,试试这个:
import ldap
ldap.set_option(ldap.OPT_REFERRALS,0)
ldap.protocol_version = 3
conn = ldap.initialize('ldap://....')
conn.simple_bind_s('user@domain.com', 'RightPassword')