Si vous utilisez le code comme suit pour usurper l'identité d'un autre utilisateur,Est-ce que la connexion par usurpation d'identité .NET est sûre pour les threads?
[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))
sur deux threads simultanés différents, vont-ils interférer avec l'autre? Par exemple, l'utilisateur actuellement connecté est-il associé au thread ou au processus hôte? J'utilise la poignée de connexion pour créer un objet WindowsImpersonationContext, en tant que champ d'état privé dans une instance d'un type I nommé "Impersonator" (code ci-dessous). Donc, puisque cet objet WindowsImpersonationContext est un champ privé local dans une instance de ce type, et qu'une nouvelle instance de ce type est créée chaque fois que je veux usurper un certain nombre d'informations d'identification, je peux supposer que ce WindowsImpersonationContext est ce qui est utilisé effectuer toutes les ACL validations lors de l'exécution de code dans un bloc tel que
using (Impersonator.Impersonate(userId, domain, password))
{
// Code I want to execute using supplied credentials
}
ce qui me préoccupe est la déclaration sur la page MSDN WindowsImpersonationContext qui dit:
tout public static (Shared en Visual Basic) Les membres de ce type sont thread safe. Tous les membres d'instance ne sont pas garantis être thread safe.
Impersonator
Classe:
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
}
À droite, j'utilise ce handle pour créer un objet WindowsImpersonationContext, qui est thread-safe (c'est une instance d'un type défini créé un par utilisation). Par "associé", je voulais dire où est cette poignée de connexion stockée? Si je comprends bien, c'est cet objet WindowsImpersonationContext qui "détient" la référence au contexte de sécurité, et si ce n'est pas partagé entre les threads, je devrais être ok ... non? –
Ce qui m'a préoccupé est l'instruction sur la page msdn http://msdn.microsoft.com/en-us/library/system.security.principal.windowsimpersonationcontext.aspx qui dit: "Toute statique publique (partagée dans Visual Basic) Les membres de ce type sont thread-safe.Tous les membres d'instance ne sont pas garantis d'être thread-safe. " –
@Charles Bretana: Les membres de l'instance de WindowsImpersonationContext ne sont PAS thread-safe. Vous ne pouvez pas faire des appels à la même instance à partir de plusieurs threads avec une sécurité garantie. Cet objet est comme la plupart des autres dans .NET, les membres d'instance ne sont pas thread-safe, les membres statiques sont. En ce qui concerne l'emplacement où le handle de connexion est stocké, le handle est dans IntPtr, qui pointe vers les informations du jeton de connexion. – casperOne