Autenticarse contra el directorio activo usando python + ldap

89

¿Cómo me autentico contra AD usando Python + LDAP? Actualmente estoy usando la biblioteca python-ldap y todo lo que produce son lágrimas.

Ni siquiera puedo enlazar para realizar una consulta simple:

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

Ejecutar esto con [email protected] password usernameme da uno de dos errores:

Invalid Credentials - Cuando escribo mal o uso intencionalmente credenciales incorrectas, no se autentica.

ldap.INVALID_CREDENTIALS: {'info': '80090308: LdapErr: DSID-0C090334, comentario: Error de AcceptSecurityContext, datos 52e, vece', 'desc': 'Credenciales no válidas'}

O

ldap.OPERATIONS_ERROR: {'info': '00000000: LdapErr: DSID-0C090627, comentario: Para realizar esta operación se debe completar un enlace exitoso en la conexión., data 0, vece', 'desc': 'Error de operaciones '}

¿Qué me estoy perdiendo para unir correctamente?

Recibo los mismos errores en Fedora y Windows.

1729
fuente
2
"... y todo lo que produce son lágrimas". ¿Las lágrimas riman con Bears o Beers?
philshem

Respuestas:

47

estaba perdido

l.set_option(ldap.OPT_REFERRALS, 0)

Desde el init.

1729
fuente
3
La causa principal de este error es que tiene referencias en la respuesta inicial y el código LDAP de Windows no envía las credenciales al servidor de referencias. Si usó credenciales de kerberos, debería funcionar.
schlenk
2
Tenía diferentes síntomas, pero esta misma opción solucionó mi problema. Lo resumió en una publicación de blog: chaverma.com/blog/index.php/2013/06/…
Chris
No estoy seguro si está relacionado, pero tuve el mismo problema y parece que la solución de 1729 hizo algo, pero a veces el servidor LDAP simplemente responde CREDENCIALES NO VÁLIDAS de inmediato. Después de un tiempo se calma y vuelve a funcionar.
Nitay
28

Si está dispuesto a usar pywin32, puede usar llamadas Win32 desde Python. Esto es lo que hacemos en nuestro servidor web CherryPy:

import win32security
token = win32security.LogonUser(
    username,
    domain,
    password,
    win32security.LOGON32_LOGON_NETWORK,
    win32security.LOGON32_PROVIDER_DEFAULT)
authenticated = bool(token)
davidavr
fuente
3
¡simple y limpio! ¡Gracias!
alexroat
Esta solución me funcionó en una aplicación Python Flask mientras estaba detrás de un proxy corporativo NTLM restrictivo. Algunas otras opciones basadas en LDAP simplemente no funcionarían.
Gigaflop
7

Eso funcionó para mí, l.set_option (ldap.OPT_REFERRALS, 0) fue la clave para acceder a ActiveDirectory. Además, creo que debería agregar un "con.unbind ()" para cerrar la conexión antes de terminar el script.

alfredocambera
fuente
8
De la documentación de python-ldap : Las instancias de LDAPObjectson devueltas por initialize(). La conexión se desvincula automáticamente y se cierra cuando se elimina el objeto LDAP.
Søren Løvborg
Cierra la sesión, no la conexión.
Romulus
5

Aquí hay un código simple que me funciona.

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

Esto se basa en una respuesta anterior .

JohnMudd
fuente
1
Esto ya no funciona, lo recibirásAttributeError: module 'ldap' has no attribute 'open'
Josh Correia
3

si tiene Kerberos instalado y hablando con AD, como sería el caso de, digamos, Centrify Express instalado y en ejecución, puede usar python-kerberos. P.ej

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

devolvería True un usuario 'joe' tiene la contraseña 'pizza' en el dominio Kerberos X.PIZZA.COM. (normalmente, creo, este último sería el mismo que el nombre del dominio AD)

Dima Pasechnik
fuente
2

Veo su comentario a @Johan Buret acerca de que el DN no soluciona su problema, pero también creo que eso es lo que debería investigar.

Dado su ejemplo, el DN para la cuenta de administrador predeterminada en AD será: cn = Administrador, cn = Usuarios, dc = mydomain, dc = co, dc = uk; por favor, inténtelo.

Daniel Bungert
fuente
2

Basado en el excelente tutorial de 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

Hice lo anterior en Python3 pero se supone que es compatible con Python 2.

Nagev
fuente
1

Traté de agregar

l.set_option (ldap.OPT_REFERRALS, 0)

pero en lugar de un error, Python simplemente se cuelga y ya no responde a nada. Tal vez estoy construyendo mal la consulta de búsqueda, ¿cuál es la parte Base de la búsqueda? Estoy usando lo mismo que el DN para el enlace simple (oh, y tuve que hacer l.simple_bind, en lugar de 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)

Estoy usando AD LDS y la instancia está registrada para la cuenta actual.

lanoxx
fuente
1

Tuve el mismo problema, pero estaba relacionado con la codificación de la contraseña.

.encode('iso-8859-1')

Resuelve el problema.

Dr.Ü
fuente
0

Utilice un nombre distinguido para iniciar sesión en su sistema. "CN=Your user,CN=Users,DC=b2t,DC=local" Debería funcionar en cualquier sistema LDAP, incluido AD

Johan Buret
fuente
0

Para mí, cambiar de simple_bind_s()a bind()funcionó.

xcl
fuente