2009-10-15 37 views
8

Microsoft tiene un artículo KB de propósito general (Q316748) que describe cómo autenticarse contra Active Directory utilizando el objeto DirectoryEntry. En su ejemplo que producen un valor de nombre de usuario mediante la concatenación del nombre de dominio y nombre de usuario en el formato de NetBIOS estándar ("dominio \ nombre de usuario") y que pasa que como parámetro al constructor entrada de directorio:¿System.DirectoryServices.DirectoryEntry contiene un constructor que realmente usa "domain username" con Ldap?

string domainAndUsername = domain + @"\" + username; 
DirectoryEntry entry = new DirectoryEntry(_path, domainAndUsername, pwd); 

Recientemente se llegó a nuestra atención de que la parte de dominio del nombre de usuario estaba siendo completamente ignorada y en múltiples entornos he confirmado este comportamiento. De hecho, el nombre de usuario y la contraseña se están utilizando, ya que la autenticación falla cuando no son válidos, pero se puede proporcionar cualquier valor arbitrario para el nombre de dominio y las pases de autenticación. A simple vista, teorizo ​​que este formato funciona para el acceso de directorio basado en WinNT, pero la parte de dominio se ignora para LDAP.

Un cheque en google muestra muchos ejemplos de LDAP que pasan un valor de "dominio \ nombre de usuario" al objeto DirectoryEntry, así que he estropeado algo en mi configuración o hay mucha gente confundida por el artículo de KB. ¿Alguien puede confirmar que este es el comportamiento esperado o recomendar una forma de aceptar valores de "dominio \ nombre de usuario" y autenticarse contra Active Directory con ellos?

Gracias,

Respuesta

18

La respuesta corta: Cuando el parámetro path del DirectoryEntry constructor contiene un nombre de dominio no válido el objeto DirectoryEntry será (después de una búsqueda sin éxito para el dominio no válido en el bosque) intentar una caída hacia atrás dejando caer la parte del dominio de el parámetro username e intento de conexión utilizando el nombre de usuario plain (sAMAccountName).

La respuesta larga: Si el nombre de dominio especificado en el parámetro username es válido pero el usuario existe en el dominio especificado en el parámetro path será autenticado el usuario (a través del uso de la fallback). Sin embargo, si el usuario existe en otro dominio en el forrest que el especificado en el parámetro path, la autenticación solo tendrá éxito cuando la parte del dominio del parámetro username esté incluida y sea correcta.

Hay cuatro formas diferentes de especificar el parámetro de nombre de usuario cuando se trata de DirectoryEntry-objetos:

  • nombre completo (CN = nombre de usuario, CN = Users, DC = dominio, DC = local)
  • NT Nombre de la cuenta (DOMINIO \ nombre de usuario)
  • Llanura cuenta Nombre/samAccountName (nombre de usuario)
  • nombre principal de usuario (generalmente [email protected])

Permítanme ilustrar con un ejemplo:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 

using System.DirectoryServices; 

namespace DirectoryTest 
{ 
    class Program 
    { 

    private static Int32 counter = 1; 

    static void Main(string[] args) 
    { 
     TestConnection(); 
    } 

    private static void TestConnection() 
    { 
     String domainOne = "LDAP://DC=domain,DC=one"; 
     String domainOneName = "DOMAINONE"; 
     String domainOneUser = "onetest"; 
     String domainOnePass = "testingONE!"; 

     String domainTwo = "LDAP://DC=domain,DC=two"; 
     String domainTwoName = "DOMAINTWO"; 
     String domainTwoUser = "twotest"; 
     String domainTwoPass = "testingTWO!"; 

     String invalidDomain = "INVALIDDOMAIN"; 

     // 1) This works because it's the correct NT Account Name in the same domain: 
     Connect(domainOne, domainOneName + "\\" + domainOneUser, domainOnePass); 

     // 2) This works because username can be supplied without the domain part 
     // (plain username = sAMAccountName): 
     Connect(domainOne, domainOneUser, domainOnePass); 

     // 3) This works because there's a fall back in DirectoryEntry to drop the domain part 
     // and attempt connection using the plain username (sAMAccountName) in (in this case) 
     // the forrest root domain: 
     Connect(domainOne, invalidDomain + "\\" + domainOneUser, domainOnePass); 

     // 4) This works because the forrest is searched for a domain matching domainTwoName: 
     Connect(domainOne, domainTwoName + "\\" + domainTwoUser, domainTwoPass); 

     // 5) This fails because domainTwoUser is not in the forrest root (domainOne) 
     // and because no domain was specified other domains are not searched: 
     Connect(domainOne, domainTwoUser, domainTwoPass); 

     // 6) This fails as well because the fallback of dropping the domain name and using 
     // the plain username fails (there's no domainTwoUser in domainOne): 
     Connect(domainOne, invalidDomain + "\\" + domainTwoUser, domainTwoPass); 

     // 7) This fails because there's no domainTwoUser in domainOneName: 
     Connect(domainOne, domainOneName + "\\" + domainTwoUser, domainTwoPass); 

     // 8) This works because there's a domainTwoUser in domainTwoName: 
     Connect(domainTwo, domainTwoName + "\\" + domainTwoUser, domainTwoPass); 

     // 9) This works because of the fallback to using plain username when connecting 
     // to domainTwo with an invalid domain name but using domainTwoUser/Pass: 
     Connect(domainTwo, invalidDomain + "\\" + domainTwoUser, domainTwoPass); 
    } 

    private static void Connect(String path, String username, String password) 
    { 
     Console.WriteLine(
     "{0}) Path: {1} User: {2} Pass: {3}", 
     counter, path, username, password); 
     DirectoryEntry de = new DirectoryEntry(path, username, password); 
     try 
     { 
     de.RefreshCache(); 
     Console.WriteLine("{0} = {1}", username, "Autenticated"); 
     } 
     catch (Exception ex) 
     { 
     Console.WriteLine("{0} ({1})", ex.Message, username); 
     } 
     Console.WriteLine(); 
     counter++; 
    } 
    } 
} 

En el ejemplo anterior domain.one es el dominio raíz del bosque y domain.two está en el mismo bosque como domain.one (pero un árbol diferente, naturalmente).

Así que para responder a su pregunta: La autenticación siempre fallará si el usuario no esté en el dominio que se va a conectar y ningún o un nombre de dominio no válido se especifica en el parámetro username.

+0

Gracias, esa es una respuesta increíblemente detallada y aprecio la claridad –

+0

mencionaste el caso "Nombre del usuario principal" ([email protected] como el formato), pero no hay un caso de prueba para eso. ¿se comportaría de la misma manera, por lo que el "@ dominio.local", cuando no es válido, causaría un retroceso en los casos 3) y 9)? – dlatikay

0

tengo dos aplicaciones que utiliza DirectoryEntry(_path, domainAndUsername, pwd); constructor y no tengo ningún problema de autenticación. Cada aplicación se instala en un cliente diferente, ambos con estructuras de dominio muy (muy) grandes.

+0

¿Hmm, y se utiliza la parte de nombre de dominio de las credenciales y se está conectando a través de LDAP? No tengo problemas de autenticación exactamente, ya que se autentica con éxito en todos los casos, pero ignora la parte del nombre de dominio. Si prefijas con un dominio no válido ¿falla la autenticación? –

+0

No puedo probarlo ahora, pero lo haré mañana y publico los resultados aquí –

Cuestiones relacionadas