2011-09-30 275 views
11

我使用類似下面的方法來模擬在我的代碼一個用戶時:獲取當前用戶名冒充

How do you do Impersonation in .NET?

在另一類,我需要找出當前用戶(如「MYDOMAIN \駝鹿「),但我不會有任何想法,如果我目前冒充另一個用戶或不。

如果我冒充了某人,我該如何獲取用戶名?

System.Environment.UserName和System.Security.Principal.WindowsIdentity.GetCurrent()。Name既返回原始用戶,也返回當前模擬的用戶。

更多詳細信息:

我這樣做模仿,這樣我可以在一元網絡共享的用戶通常不會訪問訪問某些文件。

如果我使用登錄類型的LOGON32_LOGON_INTERACTIVE,我確實看到新用戶,但我無法訪問網絡共享。如果我使用LOGON32_LOGON_NEW_CREDENTIALS(值爲9)的登錄類型,則可以訪問網絡共享,但我在Environment.UserName中看不到新用戶。

+2

它應該返回模擬的用戶。你確定你在方法調用中模擬了你查找當前用戶。 – mellamokb

+0

我剛剛使用模擬用戶訪問我登錄的用戶無權訪問的目錄進行了測試。我可以訪問該目錄,但這兩種方法仍然會返回原始用戶。一旦我停止模仿,我得到拒絕訪問嘗試訪問該目錄,所以我知道它正在模擬正確。 – Moose

+0

添加了更多詳細信息。似乎是導致問題的登錄類型。 – Moose

回答

18

BEGIN編輯: 我意識到我第一次嘗試回答這個問題並不是很清楚。所以,我想 開始另一次嘗試:

首先,我想指出的是什麼性質WindowsIdentity.GetCurrent().Name將返回 如果使用LOGON32_LOGON_NEW_CREDENTIALSLOGON32_LOGON_INTERACTIVE作爲登錄類型中的LogonUser(冒充類中)功能:

  1. 使用LOGON32_LOGON_INTERACTIVE

    // Assuming this code runs under USER_B 
    
    using (var imp = new Impersonation("treyresearch", "USER_A", "SecurePwd", LOGON32_LOGON_INTERACTIVE)) 
    { 
        // Now, we run under USER_A 
        Console.Out.WriteLine(WindowsIdentity.GetCurrent().Name); // Will return USER_A 
    } 
    
  2. 使用LOGON32_LOGON_NEW_CREDENTIALS

    // Assuming this codes runs under USER_B 
    
    using (var imp = new Impersonation("treyresearch", "USER_A", "SecurePwd", LOGON32_LOGON_NEW_CREDENTIALS)) 
    { 
        Console.Out.WriteLine(WindowsIdentity.GetCurrent().Name); // Will return USER_B 
    } 
    

這是因爲你在你的問題都說明,並與MSDN上的描述爲LogonUser功能相一致的行爲。對於LOGON32_LOGON_NEW_CREDENTIALS,創建的用戶令牌只是當前用戶令牌的克隆。這意味着創建的用戶會話與調用線程具有相同的標識符。傳遞給LogonUser函數的憑證僅用於出站網絡連接。

其次,讓我指出了兩次情況LOGON32_LOGON_INTERACTIVELOGON32_LOGON_NEW_CREDENTIALS之間所描述的差異變得清晰:

  • 兩個加入域的計算機:computer_A,computer_B
  • 兩個用戶:用戶_A(上computer_A本地管理員) ,user_B(僅B上的標準用戶權利)
  • computer_B上的一個網絡共享(mynetworkshare,user_B具有訪問共享的權限)。
  • computer_A上的一個本地文件夾(只有user_A有權寫入此文件夾)。

您在computer_A上運行程序(在user_A的帳戶下)。你模仿user_B(使用LOGON32_LOGON_INTERACTIVE)。然後,您連接到computer_B上的網絡共享並嘗試將文件複製到本地文件夾(只有user_A有權寫入此文件夾)。然後,您將收到拒絕訪問錯誤消息,因爲文件操作是使用對本地文件夾沒有權限的user_B的權限完成的。

與上述情況相同。但是現在,我們使用LOGON32_LOGON_NEW_CREDENTIALS來模擬user_B。我們連接到網絡驅動器並將文件從網絡驅動器複製到本地文件夾。在這種情況下,操作成功,因爲文件操作是通過user_A的權限完成的。

編輯完

希望,這會有所幫助。

+0

這確實有幫助。不幸的是,唯一讓我訪問我需要的網絡共享的方法是使用LOGON32_LOGON_NEW_CREDENTIALS,但後來我看不到我是誰。所以,在這種特殊情況下,我需要嘗試不使用模擬,我認爲這是真正的解決方案。我將其標記爲答案,因爲它具有關於傳遞給LogonUser()的登錄類型差異的最詳細信息。 – Moose

+0

@Moose:如果你只是需要知道你是否模仿,然後看看下面的stackoverflow問題/答案:http://stackoverflow.com/questions/3973982/how-to-tell-if-current-線程模擬 – Hans

+0

我只需要知道如何獲得用戶的身份,這給了我正是我想要的。真棒! –

1
+0

你的意思是GetTokenInformation? 如果給定從LogonUser返回的模擬令牌HANDLE,甚至不可能獲得CredHandle以提供給QueryCredentialAttributes。 –

2

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

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