2012-05-23 19 views
12

Similar a this question, estoy tratando de realizar una autenticación simple a un Active Directory 2003 usando python ldap (CentOS 6.2 x86_64, Python 2.6.6, python- ldap 2.3.10).Autenticar a Active Directory con python-ldap siempre devuelve (97, [])

A pesar de seguir todos los pasos habituales en el init, incluyendo

conn.set_option(ldap.OPT_REFERRALS, 0) 

si paso las credenciales correctas que siempre consigo un (97, []) devueltos:

>>> import ldap 
>>> conn = ldap.initialize('ldap://ad.server.domain.com') 
>>> conn.protocol_version = 3 
>>> conn.set_option(ldap.OPT_REFERRALS, 0) 
>>> conn.simple_bind_s('[email protected]', 'WrongPassword') 
ldap.INVALID_CREDENTIALS: {'info': '80090308: LdapErr: DSID-0C090334, comment: AcceptSecurityContext error, data 52e, vece', 'desc': 'Invalid credentials'} 
>>> conn.simple_bind_s('[email protected]', 'CorrectPassword') 
(97, []) 

Código de error 97 no es una éxito; es el error LDAP_REFERRAL_LIMIT_EXCEEDED que se devuelve desde AD. Tampoco puedo utilizarlo como un de facto indicador de éxito, debido a que:

>>> conn.simple_bind_s('', 'CorrectPassword') 
(97, []) 
>>> conn.simple_bind_s('', '') 
(97, []) 

Aún más frustrante es que este script es una migración de un antiguo script en Perl usando Net :: LDAP, que hace retorno 0 para un enlace autenticado exitoso al mismo AD y servidor.

Toda la información que puedo encontrar en python-ldap indica que lo que estoy haciendo debería ser Just Work; Me inclinaría a pensar que hay algo mal con los servidores AD, pero el script Perl devuelve el código LDAP correcto en un enlace exitoso.

He probado python-ldap 2.2.0 y python 2.4.4 en una vieja caja de CentOS 5.5 que tenía por ahí y "falla" exactamente de la misma manera.

¿Alguien sabe lo que me falta?

EDITAR: Por solicitud, aquí está la secuencia de comandos de Perl que funciona. Net::LDAP devuelve el código de retorno del servidor LDAP, y el servidor AD devuelve 0x00, "Solicitud exitosa", AFAICT.

#!/usr/bin/perl -w 
use strict; 
use Net::LDAP; 

## Corporate subdomains 
my @domains = ("americas", "asia", "europe"); 

# AD connect timeout 
my $timeout = 10; 
# Set AD server info. 
my $port = "389"; 
my $host = "server.domain.com"; 

my $user = shift @ARGV; 
chomp $user; 

my $password = <STDIN>; 
$password =~ s/\r\n//; 
chomp $password; 

my $ldap = Net::LDAP->new($host, port => $port, timeout => $timeout) || 
     die "Unable to connect to LDAP server"; 

my $bind_return = 1; 
foreach (@domains) { 
     my $result = $ldap->bind("$user\@$_.domain.com", password => $password); 
     if($result->code == 0) { 
       $bind_return = 0; 
       last; 
     } 
} 

## Unbind and return 
$ldap->unbind; 

if ($bind_return) { print "Authentication Failed. Access Denied\n" } 
exit $bind_return; 
+0

¿Se puede publicar el correspondiente ¿Código de Perl? – stark

+0

Supongo que para server.domain.com quieres decir ad.server.domain.com para que coincida con python? Además, el puerto predeterminado es 389 pero podría ser bueno agregar ": 389" a la URL explícitamente. – stark

Respuesta

14

Michael Ströder, el autor de la biblioteca de Python-LDAP, por lo tanto me iluminó:

El 97 no es el código de resultado LDAP. Es el resultado tipo ldap.RES_BIND. Normalmente no tiene que mirar los resultados devueltos por LDAPObject.simple_bind_s() (a menos que desee extraer los controles de respuesta bind ).

Si el código de resultado de LDAP no es 0, la excepción que lo acompaña es como ldap.INVALID_CREDENTIALS en su ejemplo.

lo tanto, su código debería tener este aspecto:

try: 
    conn.simple_bind_s('[email protected]', 'WrongPassword') 
except ldap.INVALID_CREDENTIALS: 
    user_error_msg('wrong password provided') 

La razón de estos resultados:

>>> conn.simple_bind_s('', 'CorrectPassword') 
(97, []) 
>>> conn.simple_bind_s('', '') 
(97, []) 

es que fuera de la caja 2003 Active Directory allows anonymous binds. Por lo tanto, no proporcionar una identificación de usuario aún pasará una verificación de vinculación simple, si lo único que se prueba es si simple_bind_s() arroja un error.

2003 Active Directory hace requieren autenticación para cualquier búsqueda que no son atributos de la rootDSE, por lo que para nuestros propósitos internos añadimos una búsqueda trivial para el bloque try::

try: 
    conn.simple_bind_s('[email protected]', 'SubmittedPassword') 
    conn.search_st('DC=domain,DC=com', ldap.SCOPE_SUBTREE, '(objectClass=container)', 'name', 0, 30) 
except ldap.INVALID_CREDENTIALS: 
    user_error_msg('wrong password provided') 
0

Este error significa que su conn.set_option(ldap.OPT_REFERRALS, 0) no se ve afectado.

Por lo tanto, intente esto:

import ldap 

ldap.set_option(ldap.OPT_REFERRALS,0) 
ldap.protocol_version = 3 
conn = ldap.initialize('ldap://....') 
conn.simple_bind_s('[email protected]', 'RightPassword') 
+0

No hay alegría, me temo. Todavía devuelve '(97, [])'. Verifiqué con conn.get_option() que estas opciones se estaban configurando correctamente para la instancia conn SimpleLDAPObject. –

+0

Puedo estar equivocado, pero creo que en el script de Perl, está usando 'user @ europe.domain.com'? –

Cuestiones relacionadas