使用 python-ldap 对 Active Directory 进行身份验证总是返回 (97, []) [英] Authenticating to Active Directory with python-ldap always returns (97, [])

查看:37
本文介绍了使用 python-ldap 对 Active Directory 进行身份验证总是返回 (97, [])的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

类似于这个问题,我正在尝试执行简单的使用 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, []) 返回:

<预><代码>>>>导入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,评论:AcceptSecurityContext 错误,数据 52e,vece','desc':'无效凭据'}>>>conn.simple_bind_s('user@domain.com', 'CorrectPassword')(97, [])

错误代码 97 不成功;这是从 AD 返回的 LDAP_REFERRAL_LIMIT_EXCEEDED 错误.我也不能将其用作事实上的成功指标,因为:

<预><代码>>>>conn.simple_bind_s('', '正确密码')(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使用严格;使用网络::LDAP;## 企业子域我的@domains = ("americas", "asia", "europe");# AD 连接超时我的 $timeout = 10;# 设置AD服务器信息.我的 $port = "389";我的 $host = "server.domain.com";我的 $user = shift @ARGV;chomp $user;我的 $password = <STDIN>;$password =~ s/
//;chomp $密码;我的 $ldap = Net::LDAP->new($host, port => $port, timeout => $timeout ) ||die无法连接到 LDAP 服务器";我的 $bind_return = 1;foreach (@domains) {我的 $result = $ldap->bind( "$user@$_.domain.com", password => $password );如果( $result-> 代码 == 0){$bind_return = 0;最后的;}}##解绑并返回$ldap->解除绑定;if ($bind_return) { 打印身份验证失败.拒绝访问
"}退出 $bind_return;

解决方案

Michael Ströder,python-ldap 库的作者,这样启发了我:

<块引用>

97 不是 LDAP 结果代码.这是结果类型ldap.RES_BIND.通常您不必查看返回的结果通过 LDAPObject.simple_bind_s() (除非你想提取绑定响应控制).

如果 LDAP 结果代码不是 0,则引发伴随的异常就像你的例子中的 ldap.INVALID_CREDENTIALS.

所以你的代码应该是这样的:

尝试:conn.simple_bind_s('user@domain.com', 'WrongPassword')除了 ldap.INVALID_CREDENTIALS:user_error_msg('提供的密码错误')

产生这些结果的原因:

<预><代码>>>>conn.simple_bind_s('', '正确密码')(97, [])>>>conn.simple_bind_s('', '')(97, [])

开箱即用的 2003 Active Directory 允许匿名绑定.所以根本不提供用户 ID 仍然会通过简单的绑定检查,如果唯一被测试的是 simple_bind_s() 是否抛出错误.

2003 Active Directory 确实要求对不是 rootDSE 属性的任何搜索进行身份验证,因此出于内部目的,我们向 try: 块添加了一个简单的搜索:

尝试:conn.simple_bind_s('user@domain.com', '提交密码')conn.search_st('DC=domain,DC=com', ldap.SCOPE_SUBTREE, '(objectClass=container)', 'name', 0, 30)除了 ldap.INVALID_CREDENTIALS:user_error_msg('提供的密码错误')

Similar to this question, I am trying to perform simple authentication to a 2003 Active Directory using python ldap (CentOS 6.2 x86_64, Python 2.6.6, python-ldap 2.3.10).

Despite following all the usual steps in the init, including

conn.set_option(ldap.OPT_REFERRALS, 0)

if I pass the correct credentials I always get a (97, []) returned:

>>> 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, [])

Error code 97 is not a success; it's the LDAP_REFERRAL_LIMIT_EXCEEDED error being returned from AD. Nor can I use it as a de facto success indicator, because:

>>> conn.simple_bind_s('', 'CorrectPassword')
(97, [])
>>> conn.simple_bind_s('', '')
(97, [])

Even more frustrating is that this script is a migration from an old Perl script using Net::LDAP, which does return 0 for a successful authenticated bind to the same AD and server.

All the information I can find on python-ldap indicates that what I am doing should Just Work; I would be inclined to think there's something wrong with the AD servers, but the Perl script does return the correct LDAP code on a successful bind.

I have tested python-ldap 2.2.0 and python 2.4.4 on an old CentOS 5.5 box I had lying around and it "fails" in exactly the same way.

Does anyone know what I am missing?

EDIT: Per request, here is the Perl script that works. Net::LDAP returns the return code from the LDAP server, and the AD server is returning 0x00, "Successful request", 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/
//;
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
" }
exit $bind_return;

解决方案

Michael Ströder, the author of the python-ldap library, enlightened me thus:

The 97 is not the LDAP result code. It's the result type ldap.RES_BIND. Normally you don't have to look at the results returned by LDAPObject.simple_bind_s() (unless you want to extract the bind response controls).

If the LDAP result code is not 0 the accompanying exception is raised like ldap.INVALID_CREDENTIALS in your example.

So your code should look like this:

try:
  conn.simple_bind_s('user@domain.com', 'WrongPassword')
except ldap.INVALID_CREDENTIALS:
  user_error_msg('wrong password provided')

The reason for these results:

>>> conn.simple_bind_s('', 'CorrectPassword')
(97, [])
>>> conn.simple_bind_s('', '')
(97, [])

is that out of the box 2003 Active Directory allows anonymous binds. So not providing a user id at all will still pass a simple bind check, if the only thing being tested is whether simple_bind_s() throws an error.

2003 Active Directory does require authentication for any searches that aren't attributes of the rootDSE, so for our internal purposes we added a trivial search to the try: block:

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

这篇关于使用 python-ldap 对 Active Directory 进行身份验证总是返回 (97, [])的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆