2012-03-28 19 views
9

私はコードを使用してファイル共有にアクセスするユーザーアカウントを偽装しています。次に、使用してWindowsユーザーのなりすまし

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 (new Impersonator("username", "domain", "password")) 
     { 
      Process.Start("explorer.exe", @"/root,\\server01-Prod\abc"); 
     } 

私はエラー "アクセス拒否" を取得します。

このユーザーはこのシェアにアクセスする可能性があります私はドライブをマップすることができます "ネット使用"を使用して、このコードは動作しません。今私はそれがコードだと思っています。誰かが何かを見ますか?これを行うより良い方法はありますか?

+0

これはどこから実行されていますか?これがIIS上でホストされているアプリケーションの場合、デフォルトのIISユーザーには偽装する権利がない可能性があります。 – oleksii

+0

はい。 IISでホストされているWebアプリケーション –

+0

私は同様の問題を抱えていたことを覚えています。管理者ユーザーを使用する単純なコンソールアプリケーションでこのコードを実行してみてください。私は実際にあなたがIIS上で実行されているWebアプリケーションからこれを行うことができるとは確信していません。これはASP.NETユーザーのアクセス許可(私が覚えている限り)と関係がある – oleksii

答えて

5

この試してみてください。

[DllImport("advapi32.dll", SetLastError = true)] 
    public static extern bool LogonUser(
      string lpszUsername, 
      string lpszDomain, 
      string lpszPassword, 
      int dwLogonType, 
      int dwLogonProvider, 
      out IntPtr phToken); 

用途:

IntPtr userToken = IntPtr.Zero; 

bool success = External.LogonUser(
    "john.doe", 
    "domain.com", 
    "MyPassword", 
    (int) AdvApi32Utility.LogonType.LOGON32_LOGON_INTERACTIVE, //2 
    (int) AdvApi32Utility.LogonProvider.LOGON32_PROVIDER_DEFAULT, //0 
    out userToken); 

if (!success) 
{ 
    throw new SecurityException("Logon user failed"); 
} 

using (WindowsIdentity.Impersonate(userToken)) 
{ 
Process.Start("explorer.exe", @"/root,\\server01-Prod\abc"); 
} 
+0

私は同じコードを使用していて、説明できないようなこの動作を見ています:LogonUserが終了コードを返すことがあります0とWin32Exceptionis: "System.ComponentModel.Win32Exception:ディレクトリ名が無効です"。しかし、10分後に同じ機能を再実行すると動作します。なぜあなたは知っていますか?私は、必要に応じてより多くの文脈を提供することができます。 –

1

の代わりにあなたがProcess.Startを呼び出すと、ユーザー名が含まれていProcessStartInfoインスタンスを渡すときに何が起こるか、あなたのImpersonatorクラスを使用して、パスワードをあなたがそのプロセスを実行したいドメインとは?

Impersonatorクラスが動作する場合は、ProcessStartInfoインスタンスを作成し、それを使用して新しいプロセスを作成します(クラス自体内にカプセル化します)。

var psi = new ProcessStartInfo("explorer.exe", @"/root,\\server01-Prod\abc"); 
psi.Domain = domain; 
psi.UserName = username; 
psi.Password = password; 
psi.WorkingDirectory = workingDir; 

Process.Start(psi); 

また、MSDN docsごとに...ドメイン、ユーザー名、および ProcessStartInfoオブジェクトのPasswordプロパティを設定

は、ユーザーの資格情報を使用して プロセスを開始するためにお勧めです。

異なるユーザーの資格でプロセスを開始する場合は、作業ディレクトリも設定する必要があります。

+0

エラーは表示されませんが、エクスプローラウィンドウを開くことを期待していました。 psi.Domain = "domain"; psi.UserName = "usera"; psi.Password = pwd; psi.FileName = "explorer.exe"; psi.Arguments = @ "/ root、\\ server01-pv \ abc"; psi.ErrorDialog = true; psi.UseShellExecute = false; Process.Start(psi); –

+0

'UseShellExecute = true'を設定するとどうなりますか? –

+0

さらに、 'ErrorDialog = true'を設定した場合、' UseShellExecute = true'を設定しなければならないと思いました。また、 'ProcessStartInfo'インスタンスで' WorkingDirectory'を設定します。 –

2

私が正しく理解している場合、偽装コンテキストでプロセスを実行することを意図しています。 呼び出しプロセスが別のユーザーを偽装している場合、新しいプロセスは呼び出しプロセスに対してトークンを使用し、偽装トークンは使用しません。偽装トークンによって表されるユーザーのセキュリティコンテキストで新しいプロセスを実行するには、CreateProcessAsUser関数またはCreateProcessWithLogonW関数を使用します。

あなたは、間違ったAPIを使用しています。

関連する問題