Аутентификация в Active Directory с помощью python-ldap всегда возвращает (97, [])
аналогично этот вопрос, Я пытаюсь выполнить простую аутентификацию в Active Directory 2003 с помощью python ldap (CentOS 6.2 x86_64, Python 2.6.6, python-ldap 2.3.10).
несмотря на выполнение всех обычных шагов в init, в том числе
conn.set_option(ldap.OPT_REFERRALS, 0)
если я передам правильные учетные данные I всегда получить (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 не является успешным; это LDAP_REFERRAL_LIMIT_EXCEEDED
ошибка, возвращаемая из ОБЪЯВЛЕНИЕ. Я не могу использовать его как де-факто показатель успеха, потому что:
>>> conn.simple_bind_s('', 'CorrectPassword')
(97, [])
>>> conn.simple_bind_s('', '')
(97, [])
еще больше расстраивает то, что этот скрипт является миграцией из старого скрипта Perl с использованием Net:: LDAP, который тут возвращает 0 для успешной проверки подлинности привязки к тому же AD и серверу.
вся информация, которую я могу найти на python-ldap, указывает, что то, что я делаю, должно просто работать; я был бы склонен думать, что что-то не так с рекламными серверами, но скрипт Perl возвращает правильный код LDAP при успешной привязке.
Я тестировал python-ldap 2.2.0 и python 2.4.4 на старом CentOS 5.5 box, который у меня был, и он "терпит неудачу" точно так же.
кто-нибудь знает, чего мне не хватает?
EDIT: на запрос, вот скрипт 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/rn//;
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 Deniedn" }
exit $bind_return;
2 ответов
Михаил Стродер, автор библиотеки python-ldap, просветил меня таким образом:
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 позволяет анонимно обязывает. Поэтому, не предоставляя идентификатор пользователя вообще, все равно пройдет простую проверку привязки, если единственное, что тестируется, - это simple_bind_s()
выдает ошибку.
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')
эта ошибка означает, что ваш 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')