Uwierzytelnianie w usłudze Active Directory przy użyciu python + ldap

89

Jak uwierzytelnić się w usłudze AD przy użyciu Python + LDAP. Obecnie używam biblioteki python-ldap i wszystko, co produkuje, to łzy.

Nie mogę nawet połączyć się z wykonaniem prostego zapytania:

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

Uruchomienie tego z [email protected] password usernamedaje mi jeden z dwóch błędów:

Invalid Credentials - Kiedy błędnie wpisuję lub celowo używam niewłaściwych danych uwierzytelniających, uwierzytelnianie nie jest możliwe.

ldap.INVALID_CREDENTIALS: {'info': '80090308: LdapErr: DSID-0C090334, comment: AcceptSecurityContext error, data 52e, vece', 'desc': 'Invalid credentials'}

Lub

ldap.OPERATIONS_ERROR: {'info': '00000000: LdapErr: DSID-0C090627, komentarz: Aby wykonać tę operację, połączenie musi zostać zakończone pomyślnie., data 0, vece', 'desc': 'Błąd operacji '}

Czego mi brakuje, aby prawidłowo związać?

Otrzymuję te same błędy w Fedorze i Windows.

1729
źródło
2
„... a wszystko, co wytwarza, to łzy”. Czy łzy rymują się z Niedźwiedziami czy Piwo?
philshem

Odpowiedzi:

47

Brakowało mi

l.set_option(ldap.OPT_REFERRALS, 0)

Z init.

1729
źródło
3
Główną przyczyną tego błędu jest to, że w początkowej odpowiedzi znajdują się odwołania, a kod LDAP systemu Windows nie wysyła poświadczeń do serwera odwołań. Jeśli użyłeś poświadczeń Kerberos, powinno działać.
schlenk
2
Miałem różne objawy, ale ta sama opcja rozwiązała mój problem. Podsumował to w poście na blogu: chaverma.com/blog/index.php/2013/06/…
Chris
Nie jestem pewien, czy jest to powiązane, ale miałem ten sam problem i wydaje się, że rozwiązanie 1729 coś zrobiło - ale czasami serwer LDAP po prostu natychmiast odpowiada na INVALID CREDENTIALS. Po chwili uspokaja się i znów działa.
Nitay
29

Jeśli jesteś otwarty na używanie pywin32, możesz używać wywołań Win32 z Pythona. Oto, co robimy na naszym serwerze sieciowym CherryPy:

import win32security
token = win32security.LogonUser(
    username,
    domain,
    password,
    win32security.LOGON32_LOGON_NETWORK,
    win32security.LOGON32_PROVIDER_DEFAULT)
authenticated = bool(token)
davidavr
źródło
3
proste i czyste! Dzięki!
alexroat
To rozwiązanie działało dla mnie w aplikacji Python Flask za restrykcyjnym korporacyjnym proxy NTLM. Niektóre inne opcje oparte na LDAP po prostu nie działają.
Gigaflop,
7

To zadziałało dla mnie, l.set_option (ldap.OPT_REFERRALS, 0) był kluczem do dostępu do ActiveDirectory. Ponadto myślę, że powinieneś dodać "con.unbind ()", aby zamknąć połączenie przed zakończeniem skryptu.

alfredocambera
źródło
8
Z dokumentacji python-ldap : wystąpienia LDAPObjectsą zwracane przez initialize(). Połączenie jest automatycznie odłączane i zamykane po usunięciu obiektu LDAP.
Søren Løvborg
Zamykasz sesję, a nie połączenie.
Romulus
5

Oto prosty kod, który działa dla mnie.

import ldap  # run 'pip install python-ldap' to install ldap module.
conn = ldap.open("ldaphost.company.com")
conn.simple_bind_s("[email protected]", "mypassword")

Jest to oparte na poprzedniej odpowiedzi .

JohnMudd
źródło
1
To już nie działa, otrzymaszAttributeError: module 'ldap' has no attribute 'open'
Josh Correia
3

jeśli masz zainstalowany Kerberos i rozmawiasz z AD, jak w przypadku, powiedzmy, zainstalowanego i uruchomionego Centrify Express, możesz po prostu użyć python-kerberos. Na przykład

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

zwróci True a użytkownik 'joe' ma hasło 'pizza' w krainie Kerberos X.PIZZA.COM. (myślę, że zazwyczaj ta ostatnia byłaby taka sama jak nazwa domeny AD)

Dima Pasechnik
źródło
2

Widzę twój komentarz do @Johan Buret o tym, że DN nie naprawia twojego problemu, ale uważam też, że właśnie temu powinieneś się przyjrzeć.

Biorąc pod uwagę twój przykład, nazwa wyróżniająca dla domyślnego konta administratora w AD będzie wyglądać następująco: cn = Administrator, cn = Users, dc = mydomain, dc = co, dc = uk - spróbuj tego.

Daniel Bungert
źródło
2

Oparty na doskonałym samouczku 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

Powyższe zrobiłem w Pythonie3, ale ma być kompatybilny z Pythonem 2.

Nagev
źródło
1

Próbowałem dodać

l.set_option (ldap.OPT_REFERRALS, 0)

ale zamiast błędu Python po prostu się zawiesza i nie będzie już na nic odpowiadać. Może źle buduję zapytanie wyszukiwania, jaka jest podstawowa część wyszukiwania? Używam tego samego, co DN dla prostego powiązania (och, i musiałem to zrobić l.simple_bindzamiast 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)

Używam usług LDS w usłudze AD i wystąpienie jest zarejestrowane dla bieżącego konta.

lanoxx
źródło
1

Miałem ten sam problem, ale dotyczył on kodowania hasła

.encode('iso-8859-1')

Rozwiązać problem.

Dr Ü
źródło
0

Użyj nazwy wyróżniającej, aby zalogować się do systemu. "CN=Your user,CN=Users,DC=b2t,DC=local" Powinien działać na każdym systemie LDAP, w tym na AD

Johan Buret
źródło
0

Dla mnie zmiana z simple_bind_s()na bind()załatwiła sprawę.

xcl
źródło