Authentification sur Active Directory à l'aide de python + ldap

89

Comment m'authentifier contre AD en utilisant Python + LDAP. J'utilise actuellement la bibliothèque python-ldap et tout ce qu'elle produit, ce sont des larmes.

Je ne peux même pas me lier pour effectuer une requête 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()

L'exécution de ceci avec [email protected] password usernameme donne l'une des deux erreurs suivantes:

Invalid Credentials - Lorsque je saisis mal ou que j'utilise intentionnellement de mauvaises informations d'identification, l'authentification échoue.

ldap.INVALID_CREDENTIALS: {'info': '80090308: LdapErr: DSID-0C090334, commentaire: Erreur AcceptSecurityContext, données 52e, vece', 'desc': 'Informations d'identification non valides'}

Ou

ldap.OPERATIONS_ERROR: {'info': '00000000: LdapErr: DSID-0C090627, commentaire: Pour effectuer cette opération, une liaison réussie doit être effectuée sur la connexion., data 0, vece', 'desc': 'Erreur d'opérations '}

Qu'est-ce que je manque pour lier correctement?

J'obtiens les mêmes erreurs sur fedora et windows.

1729
la source
2
"... et tout ce qu'il produit, ce sont des larmes." Les larmes riment-elles avec Ours ou Bières?
philshem

Réponses:

47

Je manquais

l.set_option(ldap.OPT_REFERRALS, 0)

À partir de l'init.

1729
la source
3
La cause première de ce bogue est que vous avez des références dans la réponse initiale et que le code LDAP Windows n'envoie pas les informations d'identification au serveur de référence. Si vous avez utilisé les informations d'identification Kerberos, cela devrait fonctionner.
schlenk
2
J'avais des symptômes différents mais cette même option a résolu mon problème. Résumée dans un article de blog: chaverma.com/blog/index.php/2013/06/…
Chris
Je ne sais pas si cela est lié, mais j'ai eu le même problème et il semble que la solution de 1729 ait fait quelque chose - Mais parfois, le serveur LDAP répond immédiatement à INVALID CREDENTIALS. Après un certain temps, il se calme et fonctionne à nouveau.
Nitay
28

Si vous êtes prêt à utiliser pywin32, vous pouvez utiliser des appels Win32 à partir de Python. Voici ce que nous faisons sur notre serveur Web CherryPy:

import win32security
token = win32security.LogonUser(
    username,
    domain,
    password,
    win32security.LOGON32_LOGON_NETWORK,
    win32security.LOGON32_PROVIDER_DEFAULT)
authenticated = bool(token)
Davidavr
la source
3
simple et propre! Merci!
alexroat
Cette solution a fonctionné pour moi dans une application Python Flask tout en étant derrière un proxy d'entreprise NTLM restrictif. Certaines autres options basées sur LDAP ne fonctionneraient tout simplement pas.
Gigaflop
7

Cela a fonctionné pour moi, l.set_option (ldap.OPT_REFERRALS, 0) était la clé pour accéder à ActiveDirectory. De plus, je pense que vous devriez ajouter un "con.unbind ()" afin de fermer la connexion avant de terminer le script.

Alfredocambera
la source
8
À partir de la documentation python-ldap : Les instances de LDAPObjectsont renvoyées par initialize(). La connexion est automatiquement dissociée et fermée lorsque l'objet LDAP est supprimé.
Søren Løvborg
Vous fermez la session, pas la connexion.
Romulus
5

Voici un code simple qui fonctionne pour moi.

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

Ceci est basé sur une réponse précédente .

JohnMudd
la source
1
Cela ne fonctionne plus, vous recevrezAttributeError: module 'ldap' has no attribute 'open'
Josh Correia
3

si Kerberos est installé et parle à AD, comme ce serait le cas avec, par exemple, Centrify Express installé et en cours d'exécution, vous pouvez simplement utiliser python-kerberos. Par exemple

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

retournerait True un utilisateur «joe» a le mot de passe «pizza» dans le royaume Kerberos X.PIZZA.COM. (typiquement, je pense, ce dernier serait le même que le nom du domaine AD)

Dima Pasechnik
la source
2

Je vois votre commentaire à @Johan Buret sur le fait que le DN ne résout pas votre problème, mais je pense aussi que c'est ce que vous devriez examiner.

Compte tenu de votre exemple, le DN du compte administrateur par défaut dans AD sera: cn = Administrator, cn = Users, dc = mydomain, dc = co, dc = uk - veuillez essayer cela.

Daniel Bungert
la source
2

Basé sur l'excellent tutoriel 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

J'ai fait ce qui précède en Python3 mais il est censé être compatible avec Python 2.

Nagev
la source
1

J'ai essayé d'ajouter

l.set_option (ldap.OPT_REFERRALS, 0)

mais au lieu d'une erreur, Python se bloque et ne répond plus à rien. Peut-être que je construis mal la requête de recherche, quelle est la partie de base de la recherche? J'utilise la même chose que le DN pour la liaison simple (oh, et je devais faire l.simple_bind, au lieu 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)

J'utilise AD LDS et l'instance est enregistrée pour le compte actuel.

lanoxx
la source
1

J'ai eu le même problème, mais il s'agissait de l'encodage du mot de passe

.encode('iso-8859-1')

Résolu le problème.

Dr.Ü
la source
0

Utilisez un nom distinctif pour vous connecter à votre système. "CN=Your user,CN=Users,DC=b2t,DC=local" Il devrait fonctionner sur n'importe quel système LDAP, y compris AD

Johan Buret
la source
0

Pour moi, passer de simple_bind_s()à a bind()fait l'affaire.

xcl
la source