2010-05-11 20 views

risposta

13

Questa è la classe wrapper abbiamo creato che ha funzionato su diverse piattaforme Windows:

public class Impersonator 
{ 
    // constants from winbase.h 
    public const int LOGON32_LOGON_INTERACTIVE = 2; 
    public const int LOGON32_LOGON_NETWORK = 3; 
    public const int LOGON32_LOGON_BATCH = 4; 
    public const int LOGON32_LOGON_SERVICE = 5; 
    public const int LOGON32_LOGON_UNLOCK = 7; 
    public const int LOGON32_LOGON_NETWORK_CLEARTEXT = 8; 
    public const int LOGON32_LOGON_NEW_CREDENTIALS = 9; 

    public const int LOGON32_PROVIDER_DEFAULT = 0; 
    public const int LOGON32_PROVIDER_WINNT35 = 1; 
    public const int LOGON32_PROVIDER_WINNT40 = 2; 
    public const int LOGON32_PROVIDER_WINNT50 = 3; 

    [DllImport("advapi32.dll", SetLastError=true)] 
    public static extern int LogonUserA(String lpszUserName, 
     String lpszDomain, 
     String lpszPassword, 
     int dwLogonType, 
     int dwLogonProvider, 
     ref IntPtr phToken); 
    [DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)] 
    public static extern int DuplicateToken(IntPtr hToken, 
     int impersonationLevel, 
     ref IntPtr hNewToken); 

    [DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)] 
    public static extern bool RevertToSelf(); 

    [DllImport("kernel32.dll", CharSet=CharSet.Auto)] 
    public static extern bool CloseHandle(IntPtr handle); 

    public static WindowsImpersonationContext LogOn(string userName, string password) 
    { 
     return LogOn(userName, password, ""); 
    } 

    public static WindowsImpersonationContext LogOn(string userName, string password, string domain) 
    { 
     WindowsIdentity tempWindowsIdentity; 
     WindowsImpersonationContext impersonationContext; 
     IntPtr token = IntPtr.Zero; 
     IntPtr tokenDuplicate = IntPtr.Zero; 

     if(RevertToSelf()) 
     { 
      if (LogonUserA(userName, domain, password, LOGON32_LOGON_NEW_CREDENTIALS, 
       LOGON32_PROVIDER_DEFAULT, ref token) != 0) 
      { 
       if (DuplicateToken(token, 2, ref tokenDuplicate) != 0) 
       { 
        tempWindowsIdentity = new WindowsIdentity(tokenDuplicate); 
        impersonationContext = tempWindowsIdentity.Impersonate(); 
        if (impersonationContext != null) 
        { 
         CloseHandle(token); 
         CloseHandle(tokenDuplicate); 
         return impersonationContext; 
        } 
       } 
      } 
      else 
      { 
       var win32 = new Win32Exception(Marshal.GetLastWin32Error()); 
       //throw new Exception(string.Format("{0}, Domain:{1}, User:{2}, Password:{3}", 
       // win32.Message, domain, userName, password)); 
       throw new Exception(win32.Message); 
      } 
     } 
     if(token!= IntPtr.Zero) 
      CloseHandle(token); 
     if(tokenDuplicate!=IntPtr.Zero) 
      CloseHandle(tokenDuplicate); 
     return null; // Failed to impersonate 
    } 

    public static bool LogOff(WindowsImpersonationContext context) 
    { 
     bool result = false; 
     try 
     { 
      if (context != null) 
      { 
       context.Undo(); 
       result = true; 
      } 
     } 
     catch 
     { 
      result = false; 
     } 
     return result; 
    } 
} 
+0

ha funzionato alla grande John. Grazie – GR7

+0

Prego, silverCORE –

+0

Dove hai trovato i valori LOGON32_PROVIDER_x? –

1

C'è una domanda simile con una grande risposta here.

Dai un'occhiata alla WindowsImpersonationContext per qualche informazione in più (anche lì è un altro esempio di codice grande lì)

+0

era curioso se poteva essere fatto senza alcun dllimports – Simon

+2

Se si tratta di un sito Web ASP.NET, allora sì può essere fatto impostando l'elemento '' nel 'web .config'. Altrimenti dovrai usare le importazioni :( – Codesleuth

+0

@Simon: la rappresentazione è utile anche durante le installazioni o l'esecuzione di un'applicazione "come" qualcun altro, ad esempio un amministratore .. – AMissico

0

Vedi ImpersonationHelper di Is it possible to safely get a SecureString value from VB .NET?. Il codice è pronto per la produzione e robusto.

Supporta IDisposable, contiene un metodo RunAs (che è di valore inestimabile), le password vengono gestite come SecureString e altri piccoli extra utili. Ho anche fornito il codice di test per la classe ImpersonationHelper estremamente utile per la risoluzione dei problemi e sono i metodi di estenzione SecureString che risultano utili.

2

ho bollito giù a due semplici metodi:

public bool ImpersonateValidUser(String userName, String domain, String password) 
public void UndoImpersonation() 

È possibile directlyh copia/incolla il codice categoria qui sotto e utilizzarlo nel progetto:

class ImpersonationContext 
    { 
     [DllImport("advapi32.dll")] 
     public static extern int LogonUserA(String lpszUserName, 
      String lpszDomain, 
      String lpszPassword, 
      int dwLogonType, 
      int dwLogonProvider, 
      ref IntPtr phToken); 
     [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)] 
     public static extern int DuplicateToken(IntPtr hToken, 
      int impersonationLevel, 
      ref IntPtr hNewToken); 

     [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)] 
     public static extern bool RevertToSelf(); 

     [DllImport("kernel32.dll", CharSet = CharSet.Auto)] 
     public static extern bool CloseHandle(IntPtr handle); 

     public const int LOGON32_LOGON_NEW_CREDENTIALS = 9; 
     public const int LOGON32_LOGON_INTERACTIVE = 2; 
     public const int LOGON32_PROVIDER_DEFAULT = 0; 
     public const int LOGON32_PROVIDER_WINNT50 = 3; 
     WindowsImpersonationContext impersonationContext; 

     public bool ImpersonateValidUser(String userName, String domain, String password) 
     { 
      WindowsIdentity tempWindowsIdentity; 
      IntPtr token = IntPtr.Zero; 
      IntPtr tokenDuplicate = IntPtr.Zero; 

      if (RevertToSelf()) 
      { 
       if (LogonUserA(userName, domain, password, LOGON32_LOGON_NEW_CREDENTIALS, 
        LOGON32_PROVIDER_WINNT50, ref token) != 0) 
       { 
        if (DuplicateToken(token, 2, ref tokenDuplicate) != 0) 
        { 
         tempWindowsIdentity = new WindowsIdentity(tokenDuplicate); 
         impersonationContext = tempWindowsIdentity.Impersonate(); 
         if (impersonationContext != null) 
         { 
          CloseHandle(token); 
          CloseHandle(tokenDuplicate); 
          return true; 
         } 
        } 
       } 
      } 
      if (token != IntPtr.Zero) 
       CloseHandle(token); 
      if (tokenDuplicate != IntPtr.Zero) 
       CloseHandle(tokenDuplicate); 
      return false; 
     } 

     public void UndoImpersonation() 
     { 
      impersonationContext.Undo(); 
     } 
    } 
+0

Certo, si riduce a due metodi. non ha errori nella gestione e se si verifica un errore, non rilascia le maniglie create. – AMissico

2

Tutti gli esempi che ho visto non riescono a t tenere conto del fatto che il tipo di accesso non è una soluzione adatta a tutte le dimensioni.

Ad esempio, questo funzionerà solo se l'utente che si sta impersonando dispone dell'autorizzazione per l'accesso al sistema di destinazione. Non sempre accade quando si accede a una casella remota di SQL Server. LOGON32_LOGON_INTERACTIVE

NetworkClearText è l'unico che funziona in modo coerente per l'utilizzo con le connessioni di SQL Server. - Nessun testo chiaro non significa che sta trasmettendo le credenziali in modo non sicuro.

Quando su un gruppo di lavoro e è necessario impersonare un utente di dominio NewCredentials è quello che funziona. (non testato con le connessioni di SQL Server)

Problemi correlati