2010-09-30 11 views
13

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 
} 

Respuesta

4

No está asociado con cualquier cosa. El identificador que tiene es un identificador de inicio de sesión. Una vez que tenga eso, use ese identificador para suplantar al usuario en un hilo (llamando al WindowsIdentity.Impersonate) o para un proceso (ya sea a través del CreateProcess API function o suplantando en el hilo y luego creando una nueva instancia Process mientras se hace pasar por un usuario).

De cualquier manera, llamando al LogonUser API function no realiza ninguna de las suplantaciones, simplemente le da un identificador de usuario que necesita para realizar la suplantación (suponiendo que tiene el privilegio).

+0

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

+0

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

+0

@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

1

Creo que quieres decir: "Si el hilo A se hace pasar por Joe y, al mismo tiempo, el hilo B se hace pasar por Fred, todo funcionará bien".

I.e. se enhebra un trabajo como Joe (y no Fred) y viceversa. La respuesta es sí; la suplantación pertenece al hilo.

Cuestiones relacionadas