2012-09-26 40 views
28

Al probar nuestra aplicación .NET 4.0 en .NET 4.5, hemos encontrado un problema con el método FindByIdentity para UserPrincipal. El siguiente código funciona cuando se ejecuta en un tiempo de ejecución .NET 4.0, pero falla en .NET 4.5:Error .NET 4.5 en UserPrincipal.FindByIdentity (System.DirectoryServices.AccountManagement)

[Test] 
public void TestIsAccountLockedOut() 
{ 
    const string activeDirectoryServer = "MyActiveDirectoryServer"; 
    const string activeDirectoryLogin = "[email protected]"; 
    const string activeDirectoryPassword = "MyADAccountPassword"; 
    const string userAccountToTest = "[email protected]"; 
    const string userPasswordToTest = "WRONGPASSWORD"; 

    var principalContext = new PrincipalContext(ContextType.Domain, activeDirectoryServer, activeDirectoryLogin, activeDirectoryPassword); 

    var isAccountLockedOut = false; 
    var isAuthenticated = principalContext.ValidateCredentials(userAccountToTest, userPasswordToTest, principalContext.Options); 
    if (!isAuthenticated) 
    { 
     // System.DirectoryServices.AccountManagement.PrincipalOperationException : Information about the domain could not be retrieved (1355). 
     using (var user = UserPrincipal.FindByIdentity(principalContext, IdentityType.UserPrincipalName, userAccountToTest)) 
     { 
      isAccountLockedOut = (user != null) && user.IsAccountLockedOut(); 
     } 
    } 
    Assert.False(isAuthenticated); 
    Assert.False(isAccountLockedOut); 
} 

Aquí es la excepción Seguimiento de la pila:

System.DirectoryServices.AccountManagement.PrincipalOperationException : Information about the domain could not be retrieved (1355). 
at System.DirectoryServices.AccountManagement.Utils.GetDcName(String computerName, String domainName, String siteName, Int32 flags) at System.DirectoryServices.AccountManagement.ADStoreCtx.LoadDomainInfo() at 
System.DirectoryServices.AccountManagement.ADStoreCtx.get_DnsDomainName() at System.DirectoryServices.AccountManagement.ADStoreCtx.GetAsPrincipal(Object storeObject, Object discriminant) at 
System.DirectoryServices.AccountManagement.ADStoreCtx.FindPrincipalByIdentRefHelper(Type principalType, String urnScheme, String urnValue, DateTime referenceDate, Boolean useSidHistory) at 
System.DirectoryServices.AccountManagement.ADStoreCtx.FindPrincipalByIdentRef(Type principalType, String urnScheme, String urnValue, DateTime referenceDate) at 
System.DirectoryServices.AccountManagement.Principal.FindByIdentityWithTypeHelper(PrincipalContext context, Type principalType, Nullable`1 identityType, String identityValue, DateTime refDate) at 
System.DirectoryServices.AccountManagement.Principal.FindByIdentityWithType(PrincipalContext context, Type principalType, IdentityType identityType, String identityValue) at 
System.DirectoryServices.AccountManagement.UserPrincipal.FindByIdentity(PrincipalContext context, IdentityType identityType, String identityValue) 

nadie más ha visto y resuelto este problema? De lo contrario, ¿hay una mejor manera de verificar el estado IsAccountLockedOut para una cuenta de Active Directory?

Como referencia, todas nuestras máquinas de prueba están dentro de la misma subred. Hay servidores ActiveDirectory separados que ejecutan Windows Server 2003, 2008 y 2012, en una variedad de modos funcionales de dominio (ver a continuación). El código funciona desde máquinas que ejecutan .NET 4.0, pero falla desde máquinas que ejecutan .NET 4.5.

Los tres .NET máquinas que nos encontramos el código de son:
- Windows 7 corriendo .NET 4.0
- Windows Vista que ejecuten .NET 4.5
- Windows Server 2012 que ejecuta .NET 4.5

El Activo servidores de directorio que hemos probado son:
- Windows 2003 con el modo funcional AD dominio establecido en Windows 2000 nativo
- Windows 2003 con el modo funcional AD dominio establecido en Windows Server 2003
- Windows 2008 con el dominio AD Modo funcional s et a Windows 2000 nativo
- Windows 2008 con el modo funcional AD dominio establecido en Windows Server 2003
- Windows 2008 con el modo funcional AD dominio establecido en Windows Server 2008
- Windows 2012 con el modo funcional AD dominio establecido en Windows 2012

Todos los servidores de Active Directory están configurados como un solo bosque simple y las máquinas cliente no son parte del dominio. No se utilizan para ninguna otra función que no sea para probar este comportamiento, y no ejecutan otra cosa que no sea Active Directory.


EDITAR - 9 oct 2012

Gracias a todos los que respondieron. A continuación se muestra un cliente de línea de comandos C# que demuestra el problema, y ​​una solución temporal a corto plazo que identificamos que no requería que cambiáramos nada sobre las configuraciones de Active Directory y DNS. Parece que la excepción solo se lanza una vez con una instancia del PrincipalContext. Incluimos los resultados para una máquina .NET 4.0 (Windows 7) y una máquina .NET 4.5 (Windows Vista).

using System; 
using System.DirectoryServices.AccountManagement; 

namespace ADBug 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      const string activeDirectoryServer = "MyActiveDirectoryServer"; 
      const string activeDirectoryLogin = "MyADAccount"; 
      const string activeDirectoryPassword = "MyADAccountPassword"; 
      const string validUserAccount = "[email protected]"; 
      const string unknownUserAccount = "[email protected]"; 

      var principalContext = new PrincipalContext(ContextType.Domain, activeDirectoryServer, activeDirectoryLogin, activeDirectoryPassword); 

      // .NET 4.0 - First attempt with a valid account finds the user 
      // .NET 4.5 - First attempt with a valid account fails with a PrincipalOperationException 
      TestFindByIdentity(principalContext, validUserAccount, "Valid Account - First Attempt"); 
      // Second attempt with a valid account finds the user 
      TestFindByIdentity(principalContext, validUserAccount, "Valid Account - Second Attempt"); 
      // First attempt with an unknown account does not find the user 
      TestFindByIdentity(principalContext, unknownUserAccount, "Unknown Account - First Attempt"); 
      // Second attempt with an unknown account does not find the user (testing false positive) 
      TestFindByIdentity(principalContext, unknownUserAccount, "Unknown Account - Second Attempt"); 
      // Subsequent attempt with a valid account still finds the user 
      TestFindByIdentity(principalContext, validUserAccount, "Valid Account - Third Attempt"); 
     } 

     private static void TestFindByIdentity(PrincipalContext principalContext, string userAccountToTest, string message) 
     { 
      var exceptionThrown = false; 
      var userFound = false; 
      try 
      { 
       using (var user = UserPrincipal.FindByIdentity(principalContext, IdentityType.UserPrincipalName, userAccountToTest)) 
       { 
        userFound = (user != null); 
       } 
      } 
      catch (PrincipalOperationException) 
      { 
       exceptionThrown = true; 
      } 
      Console.Out.WriteLine(message + " - Exception Thrown = {0}", exceptionThrown); 
      Console.Out.WriteLine(message + " - User Found = {1}", userAccountToTest, userFound); 
     } 
    } 
} 

.NET 4.0 Salida

Valid Account - First Attempt - Exception Thrown = False 
Valid Account - First Attempt - User Found = True 
Valid Account - Second Attempt - Exception Thrown = False 
Valid Account - Second Attempt - User Found = True 
Unknown Account - First Attempt - Exception Thrown = False 
Unknown Account - First Attempt - User Found = False 
Unknown Account - Second Attempt - Exception Thrown = False 
Unknown Account - Second Attempt - User Found = False 
Valid Account - Third Attempt - Exception Thrown = False 
Valid Account - Third Attempt - User Found = True 

.NET 4.5 Salida

Valid Account - First Attempt - Exception Thrown = True 
Valid Account - First Attempt - User Found = False 
Valid Account - Second Attempt - Exception Thrown = False 
Valid Account - Second Attempt - User Found = True 
Unknown Account - First Attempt - Exception Thrown = False 
Unknown Account - First Attempt - User Found = False 
Unknown Account - Second Attempt - Exception Thrown = False 
Unknown Account - Second Attempt - User Found = False 
Valid Account - Third Attempt - Exception Thrown = False 
Valid Account - Third Attempt - User Found = True 
+1

No estoy seguro de si ya ha buscado en Google esto, pero encontré una publicación con varios comentarios sobre correcciones para varios escenarios que podría causar esto: http://elegantcode.com/2009/03/21/one-scenario-where-the-systemdirectoryservices-accountmanagement-api-falls-down/ Nunca lo he visto, pero en el interés de ser útil, pensé que lo compartiría ya que me parece útil. – David

+0

por ejemplo, ha intentado pasar en DC y CN, por ejemplo PrincipalContext ctx = new PrincipalContext ( ContextType.Domain, "fabrikam.com", "CN = Usuarios, DC = fabrikam, DC = com", "administrator" , "securelyStoredPassword"); – MethodMan

+0

DJ, simplemente tratamos de pasar la cadena CN y DC, y todavía funciona bajo .NET 4.0 y falla bajo .NET 4.5. –

Respuesta

12

Estamos experimentando el mismo problema exacto (consultas entre dominios en su defecto en la actualización a 4.5) - Yo consideraría esto es un error ya que rompe el código existente (4.0).

Sin embargo, en el interés de hacer que funcione - echar un vistazo a uno de los (ahora) a falta de clientes, me di cuenta de que había un montón de peticiones DNS para los registros SRV que estaban fracasando, de la forma:

_ldap._tcp.MYSERVER1.mydomain.com,INet,Srv 
_ldap._tcp.dc._msdcs.mydomain.com,INet,Srv 

Modificar nuestro servidor DNS (el DNS utilizado por los clientes con errores) para tener una zona de reenvío para todo el tráfico de midominio.com a uno de los controladores de dominio en el dominio resolvió el problema.

con nslookup, el comportamiento de antes (cuando estaba fallando) ahora (de trabajo) era que antes de que esas consultas volverían "dominio inexistente" mientras que ahora vuelven "registros (SRV) * No ubicación de servicio disponible para ...". El punto de falla parece ser la inexistencia percibida del dominio en lugar de registros SRV perdidos. Es de esperar que MS revierte este comportamiento, pero mientras tanto, puede tener algo de suerte al crear una zona de reenvío de DNS si puede controlar el DNS para los clientes que fallan.

5

Para el OP (y para cualquier otra persona que haya ayudado con las respuestas) hemos tenido el mismo problema. En nuestro entorno de desarrollo, VS2012 instalado y nuestra aplicación se rompió en el tiempo de ejecución durante el inicio de sesión (problema AD como se señaló anteriormente). Así que hice que mi sistema se borrara y continué usando 2010, mientras derramaba lágrimas cada vez que leía una nueva entrada de blog sobre lo increíble 2012 es bla, bla.

Así que encontré este hilo gracias a Scott Hanselman. Instalé una VM en mi caja de desarrollo, Windows 8 developer 90day preview en ella, y VS2012. Puso en marcha nuestra aplicación e inmediatamente recibió el golpe AD de inicio de sesión. Simplemente envolvió nuestro FindByIdentity en una captura de prueba y lo obligó a intentar nuevamente después de la primera captura, ¡y viola funciona! Entonces, ¡gracias a quien sea que haya imaginado ese pequeño truco!

Por lo tanto, es una solución menor, y un "truco" que funciona para el desarrollo local, y no debe afectar la producción ya que no estamos poniendo 4.5 en producción en el corto plazo.

Pero el inconveniente es que localmente, registrando ahora toma como 2 minutos frente al segundo cuando nos encontramos bajo 2010 :(

Realmente no sé qué más puedo proporcionar a tratar realmente para ayudar a resolver la situación , pero pensé que compartiría mis 2 centavos de todos modos ya que esto todavía parece ser un problema importante.

+3

Gracias por los comentarios. Confirmamos el mismo comportamiento (primer intento falla, todos los posteriores tuvieron éxito) y publicamos un cliente de prueba arriba. La última respuesta que recibimos de Microsoft fue la siguiente: _ "SDS.AM en .Net4.5 agregó una restricción para requerir la resolución de DNS del dominio en el lado del cliente. Esto se diseñó como la mejor práctica DNS que debería tener una entrada DNS correcta. comentarios del foro, estamos considerando eliminar la restricción en la versión futura. "_ –

+0

¡Gracias! Una cosa que también noté es que después de agregar el primer intento de captura de falla, también hay un retraso considerable en cualquier llamada a AD, hablando 3 minutos +. ¿Hay entradas para mis hosts locales que pueda agregar para solucionar este tipo de problema? ¡Gracias de nuevo por los comentarios! – jkat98

+0

No estoy seguro de si esto está relacionado, pero siempre hemos tenido problemas importantes de rendimiento con el uso de nombres de host (por ejemplo, miservidor) en lugar de direcciones IP (por ejemplo, 192.168.14.3) para el servidor. No hemos realizado ninguna prueba de rendimiento de la solución try-catch para este problema, pero vamos a armar un caso de prueba y ver qué tipo de números se nos ocurren. –

0

Tuve el mismo problema después de actualizar el .NET Framework de 4.0 a 4.5 Tengo ugpraded framework para .net 4.5.1 y funcionó.

Cuestiones relacionadas