Si utilizando código como el siguiente de hacerse pasar por otro usuario,¿El inicio de sesión de suplantación de identidad de .NET es seguro para subprocesos?
[DllImport("advapi32.dll", SetLastError = true)]
private static extern bool
LogonUser(string lpszUsername, string lpszDomain,
string lpszPassword, int dwLogonType,
int dwLogonProvider, ref IntPtr phToken);
var handle = IntPtr.Zero;
const int LOGON32_LOGON_NETWORK = 3;
const int LOGON32_PROVIDER_DEFAULT = 0;
const int SecurityImpersonation = 2;
LogonUser(username, domain,
password, LOGON32_LOGON_NETWORK,
LOGON32_PROVIDER_DEFAULT, ref handle))
en dos subprocesos simultáneos diferentes, van a interferir uno con el otro? Es decir, ¿el usuario actualmente conectado está asociado con el hilo o con el proceso de host?
Estoy utilizando el identificador de inicio de sesión para crear un objeto WindowsImpersonationContext, como un campo de estado privado en una instancia de un tipo I llamado "Impersonator" (código a continuación). Entonces, dado que este objeto WindowsImpersonationContext es un campo privado local en una instancia de este tipo, y se crea una nueva instancia de este tipo cada vez que quiero suplantar un conjunto de credenciales, puedo suponer que este WindowsImpersonationContext es lo que se está utilizando para realizar todas las validaciones del LCA durante la ejecución de código dentro de un bloque, como
using (Impersonator.Impersonate(userId, domain, password))
{
// Code I want to execute using supplied credentials
}
lo que me tiene preocupado es la declaración en la página de MSDN WindowsImpersonationContext que dice:
estáticos públicos (Shared en Visual Basic) los miembros de este tipo son seguros para subprocesos. No se garantiza que ningún miembro de instancia sea seguro para subprocesos. clase
Impersonator
:
public class Impersonator: IDisposable
{
#region Declarations
private readonly string username;
private readonly string password;
private readonly string domain;
// This will hold the security context
// for reverting back to the client after
// impersonation operations are complete
private WindowsImpersonationContext impersonationContext;
#endregion Declarations
#region Constructors
public Impersonator(string UserName,
string Domain, string Password)
{
username = UserName;
domain = Domain;
password = Password;
}
#endregion Constructors
#region Public Methods
public static Impersonator Impersonate(
string userName, string domain, string password)
{
var imp = new Impersonator(userName, domain, password);
imp.Impersonate();
return imp;
}
public void Impersonate()
{
impersonationContext = Logon().Impersonate();
}
public void Undo() {
impersonationContext.Undo();
}
#endregion Public Methods
#region Private Methods
private WindowsIdentity Logon()
{
var handle = IntPtr.Zero;
const int LOGON32_LOGON_NETWORK = 3;
const int LOGON32_PROVIDER_DEFAULT = 0;
const int SecurityImpersonation = 2;
// Attempt to authenticate domain user account
try
{
if (!LogonUser(username, domain,
password, LOGON32_LOGON_NETWORK,
LOGON32_PROVIDER_DEFAULT, ref handle))
throw new LogonException(
"User logon failed. Error Number: " +
Marshal.GetLastWin32Error());
// ----------------------------------
var dupHandle = IntPtr.Zero;
if (!DuplicateToken(handle,
SecurityImpersonation,
ref dupHandle))
throw new LogonException(
"Logon failed attemting to duplicate handle");
// Logon Succeeded ! return new WindowsIdentity instance
return (new WindowsIdentity(handle));
}
// Close the open handle to the authenticated account
finally { CloseHandle(handle); }
}
#region external Win32 API functions
[DllImport("advapi32.dll", SetLastError = true)]
private static extern bool
LogonUser(string lpszUsername, string lpszDomain,
string lpszPassword, int dwLogonType,
int dwLogonProvider, ref IntPtr phToken);
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
private static extern bool CloseHandle(IntPtr handle);
// --------------------------------------------
[DllImport("advapi32.dll", CharSet = CharSet.Auto,
SetLastError = true)]
public static extern bool DuplicateToken(
IntPtr ExistingTokenHandle,
int SECURITY_IMPERSONATION_LEVEL,
ref IntPtr DuplicateTokenHandle);
// --------------------------------------------
#endregion external Win32 API functions
#endregion Private Methods
#region IDisposable
private bool disposed;
public void Dispose() { Dispose(true); }
public void Dispose(bool isDisposing)
{
if (disposed)
return;
if (isDisposing)
Undo();
// -----------------
disposed = true;
GC.SuppressFinalize(this);
}
~Impersonator() {
Dispose(false);
}
#endregion IDisposable
}
Derecho, utilizo ese identificador para crear un objeto WindowsImpersonationContext, que ES seguro para subprocesos (es una instancia de un tipo definido creado por cada uso). Por "asociado", quise decir dónde está almacenado ese identificador de inicio de sesión? Tal como lo entiendo, es este objeto WindowsImpersonationContext el que "contiene" la referencia al contexto de seguridad, y si esto no se comparte entre hilos, debería estar bien ... ¿no? –
Lo que me preocupa es la declaración en la página msdn http://msdn.microsoft.com/en-us/library/system.security.principal.windowsimpersonationcontext.aspx que dice: "Cualquier static público (Compartido en Visual Basic) los miembros de este tipo son seguros para subprocesos. No se garantiza que ningún miembro de instancia sea seguro para subprocesos ". –
@Charles Bretana: los miembros de instancia de la instancia de WindowsImpersonationContext NO son seguros para subprocesos. No puede hacer llamadas a la misma instancia desde múltiples hilos con seguridad garantizada. Este objeto es como la mayoría de los demás en .NET, los miembros de instancias no son seguros para subprocesos, son miembros estáticos. En cuanto a dónde se almacena el identificador de inicio de sesión, el identificador está en IntPtr, que apunta a la información del token de inicio de sesión. – casperOne