Autenticação no diretório ativo usando python + ldap

89

Como faço para autenticar no AD usando Python + LDAP. Atualmente estou usando a biblioteca python-ldap e tudo o que ela está produzindo são lágrimas.

Não consigo nem fazer uma consulta simples:

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

Executá-lo com [email protected] password usernameresulta em um de dois erros:

Invalid Credentials - Quando eu digito incorretamente ou uso intencionalmente credenciais incorretas, a autenticação falha.

ldap.INVALID_CREDENTIALS: {'info': '80090308: LdapErr: DSID-0C090334, comentário: Erro AcceptSecurityContext, dados 52e, vece', 'desc': 'Credenciais inválidas'}

Ou

ldap.OPERATIONS_ERROR: {'info': '00000000: LdapErr: DSID-0C090627, comentário: Para realizar esta operação, um vínculo bem-sucedido deve ser concluído na conexão., dados 0, vece', 'desc': 'Erro de operações '}

O que estou perdendo para vincular corretamente?

Estou recebendo os mesmos erros no fedora e no windows.

1729
fonte
2
"... e tudo o que está produzindo são lágrimas." As lágrimas rimam com ursos ou cervejas?
philshem

Respostas:

47

Estava faltando

l.set_option(ldap.OPT_REFERRALS, 0)

Do init.

1729
fonte
3
A causa raiz desse bug é que você tem referências na resposta inicial e o código do Windows LDAP não envia as credenciais para o servidor de referência. Se você usou as credenciais Kerberos, isso deve funcionar.
schlenk
2
Eu tinha sintomas diferentes, mas essa mesma opção resolveu meu problema. Resumido em uma postagem do blog: chaverma.com/blog/index.php/2013/06/…
Chris
Não tenho certeza se relacionado, mas tive o mesmo problema e parece que a solução de 1729 fez algo - Mas às vezes o servidor LDAP apenas responde CREDENCIAIS INVÁLIDAS imediatamente. Depois de um tempo, ele se acalma e funciona novamente.
Nitay
28

Se você estiver aberto para usar o pywin32, poderá usar chamadas Win32 do Python. Isso é o que fazemos em nosso servidor da web CherryPy:

import win32security
token = win32security.LogonUser(
    username,
    domain,
    password,
    win32security.LOGON32_LOGON_NETWORK,
    win32security.LOGON32_PROVIDER_DEFAULT)
authenticated = bool(token)
davidavr
fonte
3
simples e limpo! Obrigado!
alexroat
Esta solução funcionou para mim em um aplicativo Python Flask enquanto estava atrás de um proxy corporativo NTLM restritivo. Algumas outras opções baseadas em LDAP simplesmente não funcionariam.
Gigaflop
7

Isso funcionou para mim, l.set_option (ldap.OPT_REFERRALS, 0) era a chave para acessar o ActiveDirectory. Além disso, acho que você deve adicionar um "con.unbind ()" para fechar a conexão antes de terminar o script.

Alfredocambera
fonte
8
Da documentação do python-ldap : Instâncias de LDAPObjectsão retornadas por initialize(). A conexão é automaticamente desassociada e fechada quando o objeto LDAP é excluído.
Søren Løvborg
Você fecha a sessão, não a conexão.
Romulus
5

Aqui está um código simples que funciona para mim.

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

Isso é baseado em uma resposta anterior .

JohnMudd
fonte
1
Isso não funciona mais, você receberáAttributeError: module 'ldap' has no attribute 'open'
Josh Correia
3

se você tiver o Kerberos instalado e conversando com o AD, como seria o caso, digamos, do Centrify Express instalado e em execução, você pode apenas usar o python-kerberos. Por exemplo

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

retornaria True se o usuário 'joe' tiver a senha 'pizza' no domínio Kerberos X.PIZZA.COM. (normalmente, eu acho, o último seria o mesmo que o nome do domínio AD)

Dima Pasechnik
fonte
2

Vejo seu comentário para @Johan Buret sobre o DN não resolver seu problema, mas também acredito que é isso que você deve examinar.

Dado o seu exemplo, o DN para a conta de administrador padrão no AD será: cn = Administrador, cn = Usuários, dc = meudominio, dc = co, dc = uk - tente isso.

Daniel Bungert
fonte
2

Com base no excelente tutorial do 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

Eu fiz o acima em Python3, mas é suposto ser compatível com Python 2.

Nagev
fonte
1

Tentei adicionar

l.set_option (ldap.OPT_REFERRALS, 0)

mas em vez de um erro, o Python apenas trava e não responde mais a nada. Talvez eu esteja criando a consulta de pesquisa incorreta. Qual é a parte Base da pesquisa? Estou usando o mesmo DN para o vínculo simples (ah, e tive que fazer l.simple_bind, em vez 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)

Estou usando o AD LDS e a instância está registrada para a conta corrente.

lanoxx
fonte
1

Eu tive o mesmo problema, mas foi em relação à codificação de senha

.encode('iso-8859-1')

Resolveu o problema.

Dr.Ü
fonte
0

Use um nome distinto para fazer logon no seu sistema. "CN=Your user,CN=Users,DC=b2t,DC=local" Deve funcionar em qualquer sistema LDAP, incluindo AD

Johan buret
fonte
0

Para mim, mudar de simple_bind_s()para bind()funcionou.

xcl
fonte