2010-11-18 12 views
3

コードの一部を実行するためにリモートユーザーを動的に偽装する必要があります。私はネットで多く検索し、偽装するコードをいくつか持っていました。偽装するコードはリモートユーザーを動的に偽装する - c#と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 
} 

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

の下に示されていると私はローカルマシン上でユーザーを偽装しようとした場合、上記の関数を呼び出すコードは、それが正常に動作します

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:\\"); 
     } 
    } 
} 
} 

下に表示されます。私は、リモートマシン上のユーザーをimporsenateしようとした場合しかし、それは常にtestuserをとパスワードはadminで、マシン名はマシンAであるというユーザーが存在し、リモートマシンに

  Logon failure: unknown user name or bad password 

下に表示され.whichエラーを(されスローthiはドメイン名ですか?)、IPアドレスは192.168.0.33です。ワークグループはmyWorkGroupです。多くのmremoteマシンでユーザーを偽装しようとしました。しかし、リモートユーザーを偽装しようとすると、上記のエラーと同じエラーが表示されます。そして私はそれがダブルホップ問題の現れであるようにこれが見えます

答えて

1

偽装は、それがどのように見えるほど単純ではありません。偽装するコードは非常に簡単ですが、引数を見つけることは簡単ではありません。それはあなたのユーザーを認証する必要がある方法に依存します - >ワークグループは、ドメインなどがマシンとは異なります...
ユーザが両方のマシンで知っているかどうかは、ワークグループにとって重要です。簡単な技術的アプローチとして、ドメイン/マシン名を空白のままにしてください。
またリックスのポストをチェックし、偽装しworingとき、ダブルホップのものは非常に迷惑です:(

5

私はあなたの問題を理解しているように、ImpersonateDemoコードは、上記のサーバー(サーバーA)上で実行されます。

サーバーAを取得しようとしますリモートマシン(マシンA)上のファイルのリスト

サーバーA上のコードはC内のファイルを要求する場合:\ディレクトリ常にあなたのサーバーのCドライブ上のファイルを得ようとしている

理由ですローカルユーザー(ServerA上)を偽装すると、そのユーザーはマシン上にあるため動作しますドライブがオンであることを示します。リモートユーザー(MachineAから)を偽装すると、ServerAのCドライブの内容を取得しようとしていますが、そのユーザーはServerAに存在しません。

リモートマシンのIPアドレス(またはマシン名)に基づいてファイルを要求する必要があります。 TestUserがMachineAのCドライブを読み取る権限を持っている場合は、これを試してください:

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