Аутентификация в активном каталоге с использованием python + ldap

89

Как пройти аутентификацию в AD с помощью Python + LDAP. В настоящее время я использую библиотеку 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 error, data 52e, vece', 'desc': 'Invalid credentials'}

Или

ldap.OPERATIONS_ERROR: {'info': '00000000: LdapErr: DSID-0C090627, комментарий: для выполнения этой операции необходимо успешное связывание соединения., data 0, vece', 'desc': 'Ошибка операции '}

Что мне не хватает для правильного связывания?

Я получаю те же ошибки в Fedora и Windows.

1729 г.
источник
2
«... и все, что это производит, - это слезы». Есть ли слезы рифмуются с медведями или Бирс?
philshem 07

Ответы:

47

Я скучал

l.set_option(ldap.OPT_REFERRALS, 0)

Из файла init.

1729 г.
источник
3
Основная причина этой ошибки заключается в том, что у вас есть ссылки в начальном ответе, а код Windows LDAP не отправляет учетные данные на сервер ссылок. Если вы использовали учетные данные Kerberos, все должно работать.
schlenk
2
У меня были разные симптомы, но этот же вариант устранил мою проблему. Обобщил это в своем блоге: chaverma.com/blog/index.php/2013/06/…
Крис,
Не уверен, связано ли это, но у меня была та же проблема, и кажется, что решение 1729 что-то сделало - но иногда сервер LDAP просто немедленно отвечает на НЕДЕЙСТВИТЕЛЬНЫЕ УЧЕТНЫЕ ДАННЫЕ. Через некоторое время он успокаивается и снова работает.
Нитай,
29

Если вы готовы использовать pywin32, вы можете использовать вызовы Win32 из Python. Вот что мы делаем на нашем веб-сервере CherryPy:

import win32security
token = win32security.LogonUser(
    username,
    domain,
    password,
    win32security.LOGON32_LOGON_NETWORK,
    win32security.LOGON32_PROVIDER_DEFAULT)
authenticated = bool(token)
Давидавр
источник
3
просто и чисто! Благодарность!
Alexroat 02
Это решение работало для меня в приложении Python Flask за ограничительным корпоративным прокси NTLM. Некоторые другие параметры на основе LDAP просто не работают.
гигафлоп
7

Это сработало для меня, l.set_option (ldap.OPT_REFERRALS, 0) был ключом для доступа к ActiveDirectory. Более того, я считаю, что вам следует добавить con.unbind (), чтобы закрыть соединение до завершения скрипта.

альфредокамбера
источник
8
Из документации python-ldap : Экземпляры LDAPObjectвозвращаются initialize(). Соединение автоматически отключается и закрывается при удалении объекта LDAP.
Сорен Левборг
Вы закрываете сеанс, а не соединение.
Ромул
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')`

вернет True, если у пользователя joe есть пароль pizza в области Kerberos X.PIZZA.COM. (обычно, я думаю, последнее будет таким же, как имя домена AD)

Дима Пасечник
источник
2

Я вижу ваш комментарий к @Johan Buret о том, что DN не решает вашу проблему, но я также считаю, что вам следует изучить это.

В вашем примере DN для учетной записи администратора по умолчанию в AD будет: 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, и экземпляр зарегистрирован для текущей учетной записи.

Lanoxx
источник
1

У меня была такая же проблема, но она касалась кодировки пароля

.encode('iso-8859-1')

Решил проблему.

Доктор Ю.
источник
0

Используйте отличительное имя для входа в систему. "CN=Your user,CN=Users,DC=b2t,DC=local" Он должен работать в любой системе LDAP, включая AD.

Йохан Бурет
источник
0

Для меня переход с simple_bind_s()на bind()добился цели.

xcl
источник