2010-10-08 118 views
3

我需要從Web App訪問遠程驅動器。該驅動器無法訪問ASP.NET進程,因此我想模擬當前用戶的請求。模擬當前用戶使用WindowsImpersonationContext訪問網絡驅動器

我看到了一些使用WindowsImpersonationContext的基本示例,並嘗試了以下內容。

WindowsImpersonationContext impersonationContext = null; 

try 
{ 
    impersonationContext = ((WindowsIdentity)User.Identity).Impersonate(); 

    file.SaveAs(filePath); 
} 
finally 
{ 
    if (impersonationContext != null) 
    { 
     impersonationContext.Undo(); 
    } 
} 

我仍然收到拒絕訪問異常。

我讀過一些關於LogonUser的內容,但據我所知,需要用戶名和密碼才能從中獲取憑證。我不打算作爲一個不同的特定用戶登錄,只是當前用戶(誰應該有權訪問文件存儲),所以我不認爲我實際上需要LogonUser API。

有沒有人有任何想法我失蹤?上面的代碼應該工作嗎?

我還注意到,包括

<identity impersonate="true" />

不工作,但包括

<identity impersonate="true" userName="myName" password="myPassword" />

web.config

讓我進去。我見過幾個人問爲什麼這是問題,但我沒有看到任何解釋。我想知道它是否與我的問題相關。

+0

網站是否運行匿名或Windows身份? – Viv 2010-10-08 14:00:07

+0

@Vivek:IIS設置爲使用Window標識。謝謝 – fearofawhackplanet 2010-10-11 11:18:01

回答

3

您可能會遇到模擬與授權問題。當您模擬用戶時,可以以該用戶的身份訪問本地資源,但不能訪問遠程資源。通過授權,您也可以訪問遠程資源。請嘗試以下操作:

  1. 確保Windows身份驗證在IIS中啓用,並且匿名身份驗證被禁用(匿名身份驗證需要的其他身份驗證機制優先)
  2. 在你的web.config啓用<authentication mode="Windows" />確保ASP.NET處理Windows身份驗證(這應該只適用於經典管道模式)。
  3. <identity impersonate="true" />應該就夠了。

您可能需要做的另一件事是確保運行AppPool的帳戶可以像代理一樣行事。

+3

我已經完成了所有設置,並且不起作用。你能否解釋一下你最後一點的含義,*確保運行AppPool的賬戶可以像委託人一樣行事*?我不確定你的意思,你有鏈接嗎?謝謝 – fearofawhackplanet 2010-10-11 08:01:25

7

我寫了一個輔助類,做它:

public static class ImpersonationUtils 
{ 
    private const int SW_SHOW = 5; 
    private const int TOKEN_QUERY = 0x0008; 
    private const int TOKEN_DUPLICATE = 0x0002; 
    private const int TOKEN_ASSIGN_PRIMARY = 0x0001; 
    private const int STARTF_USESHOWWINDOW = 0x00000001; 
    private const int STARTF_FORCEONFEEDBACK = 0x00000040; 
    private const int CREATE_UNICODE_ENVIRONMENT = 0x00000400; 
    private const int TOKEN_IMPERSONATE = 0x0004; 
    private const int TOKEN_QUERY_SOURCE = 0x0010; 
    private const int TOKEN_ADJUST_PRIVILEGES = 0x0020; 
    private const int TOKEN_ADJUST_GROUPS = 0x0040; 
    private const int TOKEN_ADJUST_DEFAULT = 0x0080; 
    private const int TOKEN_ADJUST_SESSIONID = 0x0100; 
    private const int STANDARD_RIGHTS_REQUIRED = 0x000F0000; 
    private const int TOKEN_ALL_ACCESS = 
     STANDARD_RIGHTS_REQUIRED | 
     TOKEN_ASSIGN_PRIMARY | 
     TOKEN_DUPLICATE | 
     TOKEN_IMPERSONATE | 
     TOKEN_QUERY | 
     TOKEN_QUERY_SOURCE | 
     TOKEN_ADJUST_PRIVILEGES | 
     TOKEN_ADJUST_GROUPS | 
     TOKEN_ADJUST_DEFAULT | 
     TOKEN_ADJUST_SESSIONID; 

    [StructLayout(LayoutKind.Sequential)] 
    private struct PROCESS_INFORMATION 
    { 
     public IntPtr hProcess; 
     public IntPtr hThread; 
     public int dwProcessId; 
     public int dwThreadId; 
    } 

    [StructLayout(LayoutKind.Sequential)] 
    private struct SECURITY_ATTRIBUTES 
    { 
     public int nLength; 
     public IntPtr lpSecurityDescriptor; 
     public bool bInheritHandle; 
    } 

    [StructLayout(LayoutKind.Sequential)] 
    private struct STARTUPINFO 
    { 
     public int cb; 
     public string lpReserved; 
     public string lpDesktop; 
     public string lpTitle; 
     public int dwX; 
     public int dwY; 
     public int dwXSize; 
     public int dwYSize; 
     public int dwXCountChars; 
     public int dwYCountChars; 
     public int dwFillAttribute; 
     public int dwFlags; 
     public short wShowWindow; 
     public short cbReserved2; 
     public IntPtr lpReserved2; 
     public IntPtr hStdInput; 
     public IntPtr hStdOutput; 
     public IntPtr hStdError; 
    } 

    private enum SECURITY_IMPERSONATION_LEVEL 
    { 
     SecurityAnonymous, 
     SecurityIdentification, 
     SecurityImpersonation, 
     SecurityDelegation 
    } 

    private enum TOKEN_TYPE 
    { 
     TokenPrimary = 1, 
     TokenImpersonation 
    } 

    [DllImport("advapi32.dll", SetLastError = true)] 
    private static extern bool CreateProcessAsUser(
     IntPtr hToken, 
     string lpApplicationName, 
     string lpCommandLine, 
     ref SECURITY_ATTRIBUTES lpProcessAttributes, 
     ref SECURITY_ATTRIBUTES lpThreadAttributes, 
     bool bInheritHandles, 
     int dwCreationFlags, 
     IntPtr lpEnvironment, 
     string lpCurrentDirectory, 
     ref STARTUPINFO lpStartupInfo, 
     out PROCESS_INFORMATION lpProcessInformation); 

    [DllImport("advapi32.dll", SetLastError = true)] 
    private static extern bool DuplicateTokenEx(
     IntPtr hExistingToken, 
     int dwDesiredAccess, 
     ref SECURITY_ATTRIBUTES lpThreadAttributes, 
     int ImpersonationLevel, 
     int dwTokenType, 
     ref IntPtr phNewToken); 

    [DllImport("advapi32.dll", SetLastError = true)] 
    private static extern bool OpenProcessToken(
     IntPtr ProcessHandle, 
     int DesiredAccess, 
     ref IntPtr TokenHandle); 

    [DllImport("userenv.dll", SetLastError = true)] 
    private static extern bool CreateEnvironmentBlock(
      ref IntPtr lpEnvironment, 
      IntPtr hToken, 
      bool bInherit); 

    [DllImport("userenv.dll", SetLastError = true)] 
    private static extern bool DestroyEnvironmentBlock(
      IntPtr lpEnvironment); 

    [DllImport("kernel32.dll", SetLastError = true)] 
    private static extern bool CloseHandle(
     IntPtr hObject); 

    private static void LaunchProcessAsUser(string cmdLine, IntPtr token, IntPtr envBlock, int sessionId) 
    { 
     var pi = new PROCESS_INFORMATION(); 
     var saProcess = new SECURITY_ATTRIBUTES(); 
     var saThread = new SECURITY_ATTRIBUTES(); 
     saProcess.nLength = Marshal.SizeOf(saProcess); 
     saThread.nLength = Marshal.SizeOf(saThread); 

     var si = new STARTUPINFO(); 
     si.cb = Marshal.SizeOf(si); 
     si.lpDesktop = @"WinSta0\Default"; 
     si.dwFlags = STARTF_USESHOWWINDOW | STARTF_FORCEONFEEDBACK; 
     si.wShowWindow = SW_SHOW; 

     if (!CreateProcessAsUser(
      token, 
      null, 
      cmdLine, 
      ref saProcess, 
      ref saThread, 
      false, 
      CREATE_UNICODE_ENVIRONMENT, 
      envBlock, 
      null, 
      ref si, 
      out pi)) 
     { 
      throw new Win32Exception(Marshal.GetLastWin32Error(), "CreateProcessAsUser failed"); 
     } 
    } 

    private static IDisposable Impersonate(IntPtr token) 
    { 
     var identity = new WindowsIdentity(token); 
     return identity.Impersonate(); 
    } 

    private static IntPtr GetPrimaryToken(Process process) 
    { 
     var token = IntPtr.Zero; 
     var primaryToken = IntPtr.Zero; 

     if (OpenProcessToken(process.Handle, TOKEN_DUPLICATE, ref token)) 
     { 
      var sa = new SECURITY_ATTRIBUTES(); 
      sa.nLength = Marshal.SizeOf(sa); 

      if (!DuplicateTokenEx(
       token, 
       TOKEN_ALL_ACCESS, 
       ref sa, 
       (int)SECURITY_IMPERSONATION_LEVEL.SecurityImpersonation, 
       (int)TOKEN_TYPE.TokenPrimary, 
       ref primaryToken)) 
      { 
       throw new Win32Exception(Marshal.GetLastWin32Error(), "DuplicateTokenEx failed"); 
      } 

      CloseHandle(token); 
     } 
     else 
     { 
      throw new Win32Exception(Marshal.GetLastWin32Error(), "OpenProcessToken failed"); 
     } 

     return primaryToken; 
    } 

    private static IntPtr GetEnvironmentBlock(IntPtr token) 
    { 
     var envBlock = IntPtr.Zero; 
     if (!CreateEnvironmentBlock(ref envBlock, token, false)) 
     { 
      throw new Win32Exception(Marshal.GetLastWin32Error(), "CreateEnvironmentBlock failed"); 
     } 
     return envBlock; 
    } 

    public static void LaunchAsCurrentUser(string cmdLine) 
    { 
     var process = Process.GetProcessesByName("explorer").FirstOrDefault(); 
     if (process != null) 
     { 
      var token = GetPrimaryToken(process); 
      if (token != IntPtr.Zero) 
      { 
       var envBlock = GetEnvironmentBlock(token); 
       if (envBlock != IntPtr.Zero) 
       { 
        LaunchProcessAsUser(cmdLine, token, envBlock, process.SessionId); 
        if (!DestroyEnvironmentBlock(envBlock)) 
        { 
         throw new Win32Exception(Marshal.GetLastWin32Error(), "DestroyEnvironmentBlock failed"); 
        } 
       } 

       CloseHandle(token); 
      } 
     } 
    } 

    public static IDisposable ImpersonateCurrentUser() 
    { 
     var process = Process.GetProcessesByName("explorer").FirstOrDefault(); 
     if (process != null) 
     { 
      var token = GetPrimaryToken(process); 
      if (token != IntPtr.Zero) 
      { 
       return Impersonate(token); 
      } 
     } 

     throw new Exception("Could not find explorer.exe"); 
    } 
} 

您可以使用它像:

ImpersonationUtils.LaunchAsCurrentUser("notepad"); 

using (ImpersonationUtils.ImpersonateCurrentUser()) 
{ 

} 

更多解釋和例子,你可以在這裏找到:

Impersonating CurrentUser from SYSTEM

+0

嗨,我用你的代碼Console.WriteLine WindowsIdentity.GetCurrent()。名稱在遠程計算機上,其中另一個用戶登錄,使用psexec。它崩潰在行「if(OpenProcessToken(process.Handle,TOKEN_DUPLICATE,ref token))」拋出一個負面的錯誤代碼,我無法找出它的含義。我錯過了什麼?謝謝。編輯:我在一個域中,其中我的用戶和另一臺計算機中的用戶都是管理員 – Loaderon 2016-08-02 21:56:13

+0

我一直在這個問題上敲打我的頭2天!使用Chrome時,每次對Active Directory的調用都會崩潰。你的班級做到了!工程就像一個魅力和易於使用!謝謝!! – Philippe 2017-01-31 03:03:10