2010-11-18 14 views
3

Je souhaite emprunter l'identité d'un utilisateur distant de manière dynamique pour exécuter une partie du code. J'ai beaucoup cherché dans net et j'ai eu quelques codes pour usurper l'identité. Le code d'usurper l'identité est illustré ci-dessousImiter dynamiquement un utilisateur distant - C# et asp.net

namespace Tools 
{ 
#region Using directives. 
// ---------------------------------------------------------------------- 

using System; 
using System.Security.Principal; 
using System.Runtime.InteropServices; 
using System.ComponentModel; 

// ---------------------------------------------------------------------- 
#endregion 

///////////////////////////////////////////////////////////////////////// 

/// <summary> 
/// Impersonation of a user. Allows to execute code under another 
/// user context. 
/// Please note that the account that instantiates the Impersonator class 
/// needs to have the 'Act as part of operating system' privilege set. 
/// </summary> 
/// <remarks> 
/// This class is based on the information in the Microsoft knowledge base 
/// article http://support.microsoft.com/default.aspx?scid=kb;en-us;Q306158 
/// 
/// Encapsulate an instance into a using-directive like e.g.: 
/// 
///  ... 
///  using (new Impersonator("myUsername", "myDomainname", "myPassword")) 
///  { 
///   ... 
///   [code that executes under the new context] 
///   ... 
///  } 
///  ... 
/// 
/// Please contact the author Uwe Keim (mailto:[email protected]) 
/// for questions regarding this class. 
/// </remarks> 
public class Impersonator : 
    IDisposable 
{ 
    #region Public methods. 
    // ------------------------------------------------------------------ 

    /// <summary> 
    /// Constructor. Starts the impersonation with the given credentials. 
    /// Please note that the account that instantiates the Impersonator class 
    /// needs to have the 'Act as part of operating system' privilege set. 
    /// </summary> 
    /// <param name="userName">The name of the user to act as.</param> 
    /// <param name="domainName">The domain name of the user to act as.</param> 
    /// <param name="password">The password of the user to act as.</param> 
    public Impersonator(
     string userName, 
     string domainName, 
     string password) 
    { 
     ImpersonateValidUser(userName, domainName, password); 
    } 

    // ------------------------------------------------------------------ 
    #endregion 

    #region IDisposable member. 
    // ------------------------------------------------------------------ 

    public void Dispose() 
    { 
     UndoImpersonation(); 
    } 

    // ------------------------------------------------------------------ 
    #endregion 

    #region P/Invoke. 
    // ------------------------------------------------------------------ 

    [DllImport("advapi32.dll", SetLastError=true)] 
    private static extern int LogonUser(
     string lpszUserName, 
     string lpszDomain, 
     string lpszPassword, 
     int dwLogonType, 
     int dwLogonProvider, 
     ref IntPtr phToken); 

    [DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)] 
    private static extern int DuplicateToken(
     IntPtr hToken, 
     int impersonationLevel, 
     ref IntPtr hNewToken); 

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

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

    private const int LOGON32_LOGON_INTERACTIVE = 2; 
    private const int LOGON32_PROVIDER_DEFAULT = 0; 

    // ------------------------------------------------------------------ 
    #endregion 

    #region Private member. 
    // ------------------------------------------------------------------ 

    /// <summary> 
    /// Does the actual impersonation. 
    /// </summary> 
    /// <param name="userName">The name of the user to act as.</param> 
    /// <param name="domainName">The domain name of the user to act as.</param> 
    /// <param name="password">The password of the user to act as.</param> 
    private void ImpersonateValidUser(
     string userName, 
     string domain, 
     string password) 
    { 
     WindowsIdentity tempWindowsIdentity = null; 
     IntPtr token = IntPtr.Zero; 
     IntPtr tokenDuplicate = IntPtr.Zero; 

     try 
     { 
      if (RevertToSelf()) 
      { 
       if (LogonUser(
        userName, 
        domain, 
        password, 
        LOGON32_LOGON_INTERACTIVE, 
        LOGON32_PROVIDER_DEFAULT, 
        ref token) != 0) 
       { 
        if (DuplicateToken(token, 2, ref tokenDuplicate) != 0) 
        { 
         tempWindowsIdentity = new WindowsIdentity(tokenDuplicate); 
         impersonationContext = tempWindowsIdentity.Impersonate(); 
        } 
        else 
        { 
         throw new Win32Exception(Marshal.GetLastWin32Error()); 
        } 
       } 
       else 
       { 
        throw new Win32Exception(Marshal.GetLastWin32Error()); 
       } 
      } 
      else 
      { 
       throw new Win32Exception(Marshal.GetLastWin32Error()); 
      } 
     } 
     finally 
     { 
      if (token!= IntPtr.Zero) 
      { 
       CloseHandle(token); 
      } 
      if (tokenDuplicate!=IntPtr.Zero) 
      { 
       CloseHandle(tokenDuplicate); 
      } 
     } 
    } 

    /// <summary> 
    /// Reverts the impersonation. 
    /// </summary> 
    private void UndoImpersonation() 
    { 
     if (impersonationContext!=null) 
     { 
      impersonationContext.Undo(); 
     } 
    } 

    private WindowsImpersonationContext impersonationContext = null; 

    // ------------------------------------------------------------------ 
    #endregion 
} 

///////////////////////////////////////////////////////////////////////// 
    } 

et le code qui appelle les fonctions ci-dessus est illustré ci-dessous

using System; 
using System.IO; 
using Tools; 

namespace ImpersonatorDemo 
{ 
/// <summary> 
/// Main class for the demo application. 
/// Call this application with a low privileg account to test. 
/// </summary> 
class Program 
{ 
    /// <summary> 
    /// The main entry point. 
    /// </summary> 
    [STAThread] 
    static void Main(string[] args) 
    { 
     // Impersonate, automatically release the impersonation. format is new Impersonator("username", "domain", "password") 
     using (new Impersonator("TestUser", "MachineA", "admin")) 
     { 
      string name = Environment.UserDomainName; 
      string s = Environment.UserName; 
      // The following code is executed under the impersonated user. 
      string[] files = Directory.GetFiles("c:\\"); 
     } 
    } 
} 
} 

Il fonctionne très bien si j'essaie d'usurper l'identité d'utilisateur sur la machine locale. Mais si j'ai essayé de imporsenate un utilisateur sur la machine distante, il lance toujours une erreur .Qui est illustré ci-dessous

  Logon failure: unknown user name or bad password 

dans la machine à distance, il est un utilisateur nommé Testuser et mot de passe est admin et le nom de la machine est MachineA (est thi est le nom de domaine ??) et l'adresse IP est 192.168.0.33. le groupe de travail est myWorkGroup. J'ai essayé d'usurper l'identité des utilisateurs sur beaucoup de machines mremote. Mais il montre toujours la même erreur que j'ai écrit ci-dessus si je suis tenté d'usurper l'identité d'un utilisateur distant. et je suis sûr que ma machine locale est connectée au réseau

Répondre

1

Impersonate est pas aussi simple que ça ressemble. Bien que le code à emprunter soit assez simple, trouver les arguments peut ne pas l'être. Cela dépend de la façon dont vous devez authentifier votre utilisateur -> un groupe de travail diffère d'un domaine diffère d'une machine, etc ...
Pour votre groupe de travail, cela importe si l'utilisateur est connu sur les deux machines ou non. En tant qu'approche technique simple, essayez de laisser le nom de domaine/machine vide.
Vérifiez également après Ricks, le double truc hop est assez ennuyeux quand woring avec usurpation d'identité :(

5

Si je comprends bien votre problème, le code ImpersonateDemo passe au-dessus sur votre serveur (ServerA).

ServerA tente d'obtenir un liste des fichiers sur une machine distante (MachineA)

Si votre code sur ServerA demande les fichiers dans le répertoire C:.. \ répertoire que vous allez toujours obtenir les fichiers sur le lecteur C de votre serveur

C'est pourquoi lorsque vous empruntez l'identité d'un utilisateur local (sur ServerA) cela fonctionne - parce que l'utilisateur est sur la machine que le lecteur est allumé. Lorsque vous empruntez l'identité de l'utilisateur distant (à partir de MachineA), vous essayez toujours d'obtenir le contenu du lecteur C de ServerA, mais cet utilisateur n'existe pas sur ServerA.

Vous devez demander des fichiers en fonction de l'adresse IP (ou du nom de la machine) de la machine distante. Si le TestUser a l'autorisation de lire le lecteur C de MachineA, essayez ceci:

string[] files = Directory.GetFiles(@"\\192.168.0.33\C$"); 
string[] files = Directory.GetFiles(@"\\MachineA\C$");