2009-06-15 7 views
4

J'utilise le LogonUser win32 api:LogonUser et la délégation

token = LogonUser(...) 
WindowsIdentity newId = new WindowsIdentity(token);    
WindowsImpersonationContext impersonatedUser = newId.Impersonate(); 

Cependant lorsque vous appelez un service WCF après cela, je ne suis pas en mesure d'utiliser l'identité personnifié. Je pense que c'est parce que impersonatedUser.ImpersonationLevel est égal à l'emprunt d'identité.

Est-ce la raison? Est-ce qu'un niveau de ImpersonationLevel.Identification ce dont j'ai besoin? Comment obtenir un tel niveau?

Répondre

8

Je ne sais pas si cela fonctionnera pour WCF. Mais nous l'utilisons dans notre application Web de production pour l'usurpation d'identité pour lire et écrire des fichiers dans le système de fichiers. Vous devrez définir les API pour AdvApi32.LogonUser, AdvApi32.DuplicateToken et Kernel32.CloseHandle et assurez-vous de Fermer le WindowsImpersonationContext lorsque vous avez terminé.

/// <summary>impersonates a user</summary> 
    /// <param name="username">domain\name of the user account</param> 
    /// <param name="password">the user's password</param> 
    /// <returns>the new WindowsImpersonationContext</returns> 
    public static WindowsImpersonationContext ImpersonateUser(String username, String password) 
    { 
     WindowsIdentity winId = WindowsIdentity.GetCurrent(); 
     if (winId != null) 
     { 
      if (string.Compare(winId.Name, username, true) == 0) 
      { 
       return null; 
      } 
     } 

     //define the handles 
     IntPtr existingTokenHandle = IntPtr.Zero; 
     IntPtr duplicateTokenHandle = IntPtr.Zero; 

     String domain; 
     if (username.IndexOf("\\") > 0) 
     { 
      //split domain and name 
      String[] splitUserName = username.Split('\\'); 
      domain = splitUserName[0]; 
      username = splitUserName[1]; 
     } 
     else 
     { 
      domain = String.Empty; 
     } 

     try 
     { 
      //get a security token 

      bool isOkay = AdvApi32.LogonUser(username, domain, password, 
       (int) AdvApi32.LogonTypes.LOGON32_LOGON_INTERACTIVE, 
       (int) AdvApi32.LogonTypes.LOGON32_PROVIDER_DEFAULT, 
       ref existingTokenHandle); 

      if (!isOkay) 
      { 
       int lastWin32Error = Marshal.GetLastWin32Error(); 
       int lastError = Kernel32.GetLastError(); 

       throw new Exception("LogonUser Failed: " + lastWin32Error + " - " + lastError); 
      } 

      // copy the token 

      isOkay = AdvApi32.DuplicateToken(existingTokenHandle, 
       (int) AdvApi32.SecurityImpersonationLevel.SecurityImpersonation, 
       ref duplicateTokenHandle); 

      if (!isOkay) 
      { 
       int lastWin32Error = Marshal.GetLastWin32Error(); 
       int lastError = Kernel32.GetLastError(); 
       Kernel32.CloseHandle(existingTokenHandle); 
       throw new Exception("DuplicateToken Failed: " + lastWin32Error + " - " + lastError); 
      } 
      // create an identity from the token 

      WindowsIdentity newId = new WindowsIdentity(duplicateTokenHandle); 
      WindowsImpersonationContext impersonatedUser = newId.Impersonate(); 

      return impersonatedUser; 
     } 
     finally 
     { 
      //free all handles 
      if (existingTokenHandle != IntPtr.Zero) 
      { 
       Kernel32.CloseHandle(existingTokenHandle); 
      } 
      if (duplicateTokenHandle != IntPtr.Zero) 
      { 
       Kernel32.CloseHandle(duplicateTokenHandle); 
      } 
     } 
    } 
+0

Remarque pour ceux qui sont intéressés par la création d'instances de WindowsIdentity: 'WindowsIdentity.Dispose()' ferme son handle de jeton, ce qui signifie que vous n'avez pas besoin d'appeler 'CloseHandle (duplicateTokenHandle)' si vous appelez 'Dispose'. – Joh

+0

@Joh - Je ne pense pas que ce soit correct. 'Dispose' * does * appelle' CloseHandle() ', mais pas sur le handle passé dans le constructeur. Le constructeur duplique la poignée fournie. c'est le double qui est fermé dans 'Dispose'. – Olly

1

après cela, je ne suis pas en mesure d'utiliser l'identité personnifié

L'usurpation d'identité devrait être efficace pour l'accès sur la même case, mais pas sur le réseau. Il peut être, comme le montre le code de consultutah, qu'il suffit d'appeler DuplicateToken() pour convertir le jeton d'ouverture de session en jeton d'emprunt d'identité avant de pouvoir l'utiliser.

Je pense que c'est parce que impersonatedUser.ImpersonationLevel est égal à Impersonation.

Si vous devez agir en tant qu'utilisateur usurpé sur d'autres systèmes, vous avez besoin d'un niveau plus élevé d'usurpation d'identité appelé 'délégation'. C'est fondamentalement équivalent à avoir le mot de passe de l'utilisateur afin que vous puissiez vous représenter comme eux à d'autres.

Questions connexes