Олицетворение пользователя 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-Prodabc");
        }

Я получаю ошибку "Доступ запрещен".

этот пользователь предположительно имеет доступ к этому ресурсу. Я могу сопоставить диск, использовать "net use", но этот код не будет работать. Теперь я думаю, что это код. Кто-нибудь что-нибудь видит? Есть ли лучший способ сделать это?

3 ответов


попробуйте это :

[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");
}

Если я правильно понимаю, ваше намерение состоит в том, чтобы запустить процесс в контексте олицетворения.

документ из CreateProcess (который используется процессом.Начала) говорит: Если вызывающий процесс от имени другого пользователя, новый процесс использует маркер для вызывающего процесса, а не маркер олицетворения. Чтобы запустить новый процесс в контексте безопасности пользователя, представленного маркером олицетворения, используйте CreateProcessAsUser или CreateProcessWithLogonW функция.

Итак, вы используете неправильный API для этого.


вместо Impersonator класс, что происходит, когда вы называете Process.Start и передать ProcessStartInfo экземпляр, который содержит имя пользователя, пароль и домен, который вы хотите запустить процесс?

возможно, если это работает, то ваш 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...

настройка свойств домена, имени пользователя и пароля в Объект ProcessStartInfo рекомендуется для запуска процесс с учетными данными пользователя.

вы также должны установить рабочий каталог при запуске процесса с различными пользовательскими кредитами.