2010-09-30 9 views
13

Se si utilizza il codice quanto segue di impersonare un altro utente,L'accesso tramite impersonation .NET è thread-safe?

[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)) 

su due diversi thread concorrenti, faranno interferiscono uno con l'altro? Ad esempio, l'utente attualmente connesso è associato al thread o al processo host?

Sto utilizzando l'handle di accesso per creare un oggetto WindowsImpersonationContext, come campo di stato privato in un'istanza di un tipo denominato "Impersonator" (codice di seguito). Quindi, poiché questo oggetto WindowsImpersonationContext è un campo privato locale in un'istanza di questo tipo e viene creata una nuova istanza di questo tipo ogni volta che voglio impersonare un gruppo di credenziali, posso presumere che questo WindowsImpersonationContext sia quello a cui si sta abituando eseguire tutte le convalide ACL durante l'esecuzione di codice all'interno di un blocco come

using (Impersonator.Impersonate(userId, domain, password)) 
    { 
     // Code I want to execute using supplied credentials 
    } 

cosa mi ha preoccupato è la dichiarazione sulla pagina MSDN WindowsImpersonationContext che dice:

statici pubblici (Shared in Visual Basic) membri di questo tipo sono thread-safe. Non è garantito che tutti i membri di istanza siano 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 
} 

risposta

4

Non è associato con qualsiasi cosa. L'handle che hai è un handle di accesso. Una volta che avete, è utilizzare l'impugnatura per rappresentare l'utente su un thread (chiamando WindowsIdentity.Impersonate) o per un processo (sia attraverso il CreateProcess API function o impersonando sul filo e quindi la creazione di una nuova istanza Process durante la rappresentazione di un utente).

In entrambi i casi, chiamare lo LogonUser API function non esegue alcuna rappresentazione, fornisce semplicemente un handle utente di cui è necessario eseguire la rappresentazione (presupponendo che si disponga del privilegio).

+0

destro, io uso l'impugnatura per creare un oggetto WindowsImpersonationContext, che è thread-safe, (è un esempio di un tipo definito creato uno ad utilizzo). Con "associato", intendevo dire dove è memorizzato quel logon di accesso? A quanto ho capito, è questo oggetto WindowsImpersonationContext che "contiene" il riferimento al contesto di sicurezza, e se questo non è condiviso su thread, dovrei essere ok ... giusto? –

+0

Quello che mi ha preoccupato è la dichiarazione sulla pagina http://msdn.microsoft.com/en-us/library/system.security.principal.windowsimpersonationcontext.aspx MSDN che dice: "statici pubblici (Shared in Visual Basic) i membri di questo tipo sono thread-safe. Non è garantito che tutti i membri di istanza siano thread-safe. " –

+0

@Charles Bretana: i membri dell'istanza dell'istanza WindowsImpersonationContext non sono thread-safe. Non è possibile effettuare chiamate alla stessa istanza da più thread con sicurezza garantita. Questo oggetto è come la maggior parte degli altri in .NET, i membri di istanza non sono thread-safe, i membri statici lo sono. Per quanto riguarda la posizione in cui è archiviato l'handle di accesso, l'handle si trova in IntPtr, che indica le informazioni per il token di accesso. – casperOne

1

Penso che si intende: "Se thread A impersona Joe e al tempo stesso filo B impersona Fred lo farà tutto il lavoro OK."

I.e. filerà A come Joe (e non Fred) e viceversa. La risposta è si; la rappresentazione appartiene al thread.