Олицетворение текущего пользователя, использующего WindowsImpersonationContext для доступа к сетевому диску - PullRequest
3 голосов
/ 08 октября 2010

Мне нужно получить доступ к удаленному диску из веб-приложения. Диск недоступен процессу ASP.NET, поэтому я хочу выдать себя за текущего пользователя для запроса.

Я видел несколько основных примеров использования 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 впускает меня. Я видел, как несколько человек задают вопросы о том, почему это так, но я не видел объяснений. Мне интересно, связано ли это с моей проблемой.

Ответы [ 2 ]

9 голосов
/ 27 января 2013

Я написал вспомогательный класс, который делает это:

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

3 голосов
/ 08 октября 2010

Возможно, вы столкнулись с проблемой «Олицетворение против делегирования».Когда вы олицетворяете пользователя, вы можете получить доступ к локальным ресурсам как этот пользователь, но не к удаленным ресурсам.С делегированием вы также можете получить доступ к удаленным ресурсам.Попробуйте следующее:

  1. Убедитесь, что аутентификация Windows включена в IIS и анонимная аутентификация отключена (анонимная аутентификация имеет приоритет над другими механизмами аутентификации)
  2. Включите <authentication mode="Windows" /> в вашемweb.config, чтобы гарантировать, что ASP.NET обрабатывает аутентификацию Windows (это должно применяться только к классическому конвейерному режиму).
  3. <identity impersonate="true" /> должно быть достаточно.

Другая вещь, которая может вам понадобитьсячтобы убедиться, что учетной записи, на которой запущен AppPool, разрешено действовать как делегат.

...