2010-09-30 4 views
13

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 
} 

Répondre

4

Il est pas associé à quoi que ce soit. Le handle que vous avez est un handle de connexion. Une fois que vous avez cela, vous utilisez ce handle pour emprunter l'identité d'un thread (en appelant WindowsIdentity.Impersonate) ou pour un processus (via le CreateProcess API function ou en usurpant l'identité sur le thread, puis en créant une nouvelle instance Process en usurpant l'identité d'un utilisateur).

De toute façon, l'appel du LogonUser API function n'implique aucune usurpation d'identité, il vous donne simplement un handle d'utilisateur dont vous avez besoin pour effectuer l'emprunt d'identité (en supposant que vous ayez le privilège).

+0

À 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? –

+0

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. " –

+0

@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

1

Je pense que vous voulez dire: "Si le thread A usurpe l'identité de Joe et en même temps le thread B usurpe Fred, tout ira bien."

I.e. va filer un travail comme Joe (et non Fred) et vice versa. La réponse est oui; l'usurpation appartient au fil.

Questions connexes