Получение текущего имени пользователя при выдаче заимствований
Я использую что-то вроде следующего метода для олицетворения пользователя в моем коде:
Как вы выполняете олицетворение в .NET?
В другом классе мне нужно узнать текущего пользователя (например, "mydomain\moose" ), но я не буду иметь никакой идеи, если я в настоящее время выдаю себя за другого пользователя или нет.
Как получить имя пользователя, если я выдаю себя за кого-то?
System.Environment.UserName и System.Security.Principal.WindowsIdentity.GetCurrent(). Имя и возвращают оригинального пользователя, а не текущего пользователя.
Подробнее:
Я делаю это олицетворение, чтобы я мог получить доступ к некоторым файлам в общем сетевом ресурсе, к которому пользователь обычно не имеет доступа.
Если я использую тип входа LOGON32_LOGON_INTERACTIVE, я вижу нового пользователя, но я не могу получить доступ к общему ресурсу сети. Если я использую тип входа LOGON32_LOGON_NEW_CREDENTIALS (значение 9), я могу получить доступ к общему сетевому ресурсу, но я не вижу нового пользователя в Environment.UserName.
Ответы
Ответ 1
Во-первых, я хотел бы указать, что свойство WindowsIdentity.GetCurrent().Name
будет возвращать, если вы используете LOGON32_LOGON_NEW_CREDENTIALS
или LOGON32_LOGON_INTERACTIVE
качестве типа входа для функции LogonUser (внутри класса олицетворения):
-
Использование 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
}
-
Использование 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_INTERACTIVE
и LOGON32_LOGON_NEW_CREDENTIALS
:
- Два присоединенных к домену компьютера: компьютер_А, компьютер_В
- Два пользователя: user_A (локальный администратор на компьютере_A), user_B (только стандартные права пользователя на B)
- Один сетевой ресурс на компьютере_B (mynetworkshare, user_B имеет разрешение на доступ к общему ресурсу).
- Одна локальная папка на компьютере_А (только пользователь_А имеет разрешение на запись в эту папку).
Вы запускаете свою программу на компьютере_А (под учетной записью пользователя_А). Вы олицетворяете пользователя Б (используя LOGON32_LOGON_INTERACTIVE
). Затем вы подключаетесь к общему сетевому ресурсу на компьютере computer_B и пытаетесь скопировать файл в локальную папку (только у пользователя user_A есть разрешение на запись в эту папку). Затем вы получаете сообщение об ошибке "Отказано в доступе", поскольку файловая операция выполняется с разрешениями пользователя user_B, у которого нет прав доступа к локальной папке.
Та же ситуация, что и выше. Но теперь мы используем LOGON32_LOGON_NEW_CREDENTIALS
для олицетворения user_B. Мы подключаемся к сетевому диску и копируем файл с сетевого диска в локальную папку. В этом случае операция завершается успешно, потому что файловая операция выполняется с разрешениями user_A.
Ответ 2
В соответствии с примером в http://msdn.microsoft.com/en-us/library/chf6fbt4.aspx текущая идентификация изменяется во время олицетворения. Вы уверены, что ваш код находится внутри выведенного кода?
Ответ 3
Я написал вспомогательный класс, который делает это:
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())
{
}
Дополнительные пояснения и примеры можно найти здесь:
Выдача себя в действие с помощью CurrentUser из SYSTEM
Ответ 4
Взгляните на QueryCredentialsAttributes
.