Error de .NET 4.5 en UserPrincipal.FindByIdentity (System.DirectoryServices.AccountManagement)
Al probar nuestra aplicación .NET 4.0 bajo .NET 4.5, hemos encontrado un problema con elFindByIdentity
método paraUserPrincipal
. El siguiente código funciona cuando se ejecuta en un tiempo de ejecución de .NET 4.0, pero falla en .NET 4.5:
[Test]
public void TestIsAccountLockedOut()
{
const string activeDirectoryServer = "MyActiveDirectoryServer";
const string activeDirectoryLogin = "MyADAccount@MyDomain";
const string activeDirectoryPassword = "MyADAccountPassword";
const string userAccountToTest = "TestUser@MyDomain";
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í está el rastro de la pila de excepción:
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)
¿Alguien más ha visto y resuelto este problema? Si no es así, ¿hay alguna manera mejor para que revisemos elIsAccountLockedOut
estado de una cuenta de Active Directory?
Para 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 más abajo). El código funciona desde máquinas que ejecutan .NET 4.0, pero falla desde máquinas que ejecutan .NET 4.5.
Las tres máquinas .NET desde las que ejecutamos el código son:
- Windows 7 ejecutando .NET 4.0
- Windows Vista ejecutando .NET 4.5
- Windows Server 2012 ejecutando .NET 4.5
Los servidores de Active Directory que hemos probado son:
- Windows 2003 con el modo funcional de dominio AD configurado en Windows 2000 nativo
- Windows 2003 con el modo funcional de dominio AD configurado para Windows Server 2003
- Windows 2008 con el modo funcional de dominio AD configurado en Windows 2000 nativo
- Windows 2008 con el modo funcional de dominio AD configurado para Windows Server 2003
- Windows 2008 con el modo funcional de dominio AD configurado para Windows Server 2008
- Windows 2012 con el modo funcional de dominio AD configurado para Windows 2012
Todos esos servidores de Active Directory están configurados como un simple bosque único, y las máquinas cliente no forman parte del dominio. No se usan para ninguna otra función que no sea 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 de C # que demuestra el problema y una solución a corto plazo que identificamos que no nos obligó a cambiar nada acerca de las configuraciones de Active Directory y DNS. Parece que la excepción solo se lanza una vez con una instancia de PrincipalContext. Incluimos las salidas 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);
}
}
}
Salida .NET 4.0
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
Salida .NET 4.5
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