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

ASP.NET: выдавать себя за домен в VMWare

Этот вопрос я задаю, но в ответе не содержится подробностей о том, как получается _token. Кажется, использовать только WindowsIdentity.GetCurrent().Token так что никакого подражания не происходит.

Могу ли я выдавать себя за пользователя в другом домене Active Directory в.NET?

На этот следующий вопрос есть противоречивые ответы, причем на принятый ответ дается комментарий: "Я начинаю подозревать, что моя проблема лежит в другом месте". Не полезно.

LogonUser работает только для моего домена

Следующий вопрос, по-видимому, подразумевает, что это невозможно, но он касается двух доменов, поэтому я не уверен, что это актуально.

Мой настоящий вопрос:

  • Является ли это возможным? И если это так,
  • Как? или где я ошибся?

До сих пор я пробовал использовать код с http://msdn.microsoft.com/en-us/library/chf6fbt4%28v=VS.80%29.aspx

bool returnValue = LogonUser(user, domain, password,
            LOGON32_LOGON_NETWORK, LOGON32_PROVIDER_DEFAULT,
            ref tokenHandle);
// after this point, returnValue = false

Ошибка Win32

Ошибка входа: неизвестное имя пользователя или неверный пароль

7 ответов

Очень немногие посты предлагают использовать LOGON_TYPE_NEW_CREDENTIALS вместо LOGON_TYPE_NETWORK или же LOGON_TYPE_INTERACTIVE, У меня была проблема олицетворения, когда одна машина была подключена к домену, а другая - нет, и это исправило ее. Последний фрагмент кода в этом посте предполагает, что олицетворение в лесу действительно работает, но в нем ничего не говорится о настройке доверия. Так что, возможно, стоит попробовать:

const int LOGON_TYPE_NEW_CREDENTIALS = 9;
const int LOGON32_PROVIDER_WINNT50 = 3;
bool returnValue = LogonUser(user, domain, password,
            LOGON_TYPE_NEW_CREDENTIALS, LOGON32_PROVIDER_WINNT50,
            ref tokenHandle);

MSDN говорит, что LOGON_TYPE_NEW_CREDENTIALS работает только при использовании LOGON32_PROVIDER_WINNT50,

Это работает для меня, полный рабочий пример (я хотел бы, чтобы больше людей делали это):

//logon impersonation
using System.Runtime.InteropServices; // DllImport
using System.Security.Principal; // WindowsImpersonationContext
using System.Security.Permissions; // PermissionSetAttribute

...

class Program {

    // obtains user token
    [DllImport("advapi32.dll", SetLastError = true)]
    public static extern bool LogonUser(string pszUsername, string pszDomain, string pszPassword,
        int dwLogonType, int dwLogonProvider, ref IntPtr phToken);

    // closes open handes returned by LogonUser
    [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
    public extern static bool CloseHandle(IntPtr handle);

    public void DoWorkUnderImpersonation() {
        //elevate privileges before doing file copy to handle domain security
        WindowsImpersonationContext impersonationContext = null;
        IntPtr userHandle = IntPtr.Zero;
        const int LOGON32_PROVIDER_DEFAULT = 0;
        const int LOGON32_LOGON_INTERACTIVE = 2;
        string domain = ConfigurationManager.AppSettings["ImpersonationDomain"];
        string user = ConfigurationManager.AppSettings["ImpersonationUser"];
        string password = ConfigurationManager.AppSettings["ImpersonationPassword"];

        try {
            Console.WriteLine("windows identify before impersonation: " + WindowsIdentity.GetCurrent().Name);

            // if domain name was blank, assume local machine
            if (domain == "")
                domain = System.Environment.MachineName;

            // Call LogonUser to get a token for the user
            bool loggedOn = LogonUser(user,
                                        domain,
                                        password,
                                        LOGON32_LOGON_INTERACTIVE,
                                        LOGON32_PROVIDER_DEFAULT,
                                        ref userHandle);

            if (!loggedOn) {
                Console.WriteLine("Exception impersonating user, error code: " + Marshal.GetLastWin32Error());
                return;
            }

            // Begin impersonating the user
            impersonationContext = WindowsIdentity.Impersonate(userHandle);

            Console.WriteLine("Main() windows identify after impersonation: " + WindowsIdentity.GetCurrent().Name);

            //run the program with elevated privileges (like file copying from a domain server)
            DoWork();

        } catch (Exception ex) {
            Console.WriteLine("Exception impersonating user: " + ex.Message);
        } finally {
            // Clean up
            if (impersonationContext != null) {
                impersonationContext.Undo();
            }

            if (userHandle != IntPtr.Zero) {
                CloseHandle(userHandle);
            }
        }
    }


    private void DoWork() {
        //everything in here has elevated privileges

        //example access files on a network share through e$ 
        string[] files = System.IO.Directory.GetFiles(@"\\domainserver\e$\images", "*.jpg");
    }
}

Мне удалось выдать себя за пользователя в другом домене, но только с доверием, установленным между двумя доменами.

var token = IntPtr.Zero;
var result = LogonUser(userID, domain, password, LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, ref token);
if (result)
{
    return WindowsIdentity.Impersonate(token);
}

Лучше использовать SecureString:

var password = new SecureString();
var phPassword phPassword = Marshal.SecureStringToGlobalAllocUnicode(password);
IntPtr phUserToken;
LogonUser(username, domain, phPassword, LOGON32_LOGON_INTERACTIVE,  LOGON32_PROVIDER_DEFAULT, out phUserToken);

А также:

Marshal.ZeroFreeGlobalAllocUnicode(phPassword);
password.Dispose();

Определение функции:

private static extern bool LogonUser(
  string pszUserName,
  string pszDomain,
  IntPtr pszPassword,
  int dwLogonType,
  int dwLogonProvider,
  out IntPtr phToken);

У меня была такая же проблема. Не знаю, решили вы это или нет, но я действительно пытался получить доступ к общему сетевому ресурсу с помощью учетных данных AD. WNetAddConnection2() это то, что вам нужно использовать в этом случае.

Проблема, с которой я столкнулся, заключалась в том, что моя рабочая станция находилась в одном домене, но мне нужно было пройти аутентификацию на сервере в другом домене:

  • ОШИБКА: "Exception impersonating user, error code: 1326"
  • РЕШЕНИЕ: добавлено LOGON32_LOGON_NEW_CREDENTIALSкак запасной вариант Impersonate/LogonUser()

Олицетворение.cs

      using System;
using System.Runtime.InteropServices;
using System.Security.Principal;

namespace TestDBAccess
{
    public class Impersonation : IDisposable
    {
        [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
        public static extern bool LogonUser(String Username, String Domain, String Password, int LogonType, int LogonProvider, out IntPtr Token);
        [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
        public extern static bool CloseHandle(IntPtr handle);

        public const int LOGON32_PROVIDER_DEFAULT = 0;
        public const int LOGON32_LOGON_INTERACTIVE = 2;
        public const int LOGON32_LOGON_NETWORK = 3;
        public const int LOGON32_LOGON_BATCH = 4;
        public const int LOGON32_LOGON_SERVICE = 5;
        public const int LOGON32_LOGON_UNLOCK = 7;
        public const int LOGON32_LOGON_NETWORK_CLEARTEXT = 8;
        public const int LOGON32_LOGON_NEW_CREDENTIALS = 9;

        private WindowsImpersonationContext impersonationContext = null;
        private IntPtr userHandle = IntPtr.Zero;

        public Impersonation(string user, string domain, string password)
        {
            // Extract domain/username from user string
            string[] principal = user.Split('\\');
            if (principal.Length == 2)
            {
                domain = principal[0];
                user = principal[1];
            }
            if (string.IsNullOrEmpty(domain))
                domain = GetDefaultDomain();

            // Call LogonUser to get a token for the user
            bool loggedOn =
                LogonUser(user, domain, password, LOGON32_LOGON_INTERACTIVE,
                    LOGON32_PROVIDER_DEFAULT, out userHandle);
            if (!loggedOn)
            {
                int ierr = Marshal.GetLastWin32Error();
                if (ierr == 1326)
                {
                    loggedOn =
                        LogonUser(user, domain, password, LOGON32_LOGON_NEW_CREDENTIALS,
                            LOGON32_PROVIDER_DEFAULT, out userHandle);
                }
                if (!loggedOn)
                    throw new Exception("Exception impersonating user, error code: " + Marshal.GetLastWin32Error());
            }

            // Begin impersonating the user
            impersonationContext = WindowsIdentity.Impersonate(userHandle);
        }

        public static string GetDefaultDomain ()
        {
            return System.Environment.UserDomainName;
        }

        public void Dispose()
        {
            // Clean up
            if (impersonationContext != null)
                impersonationContext.Undo();

            if (userHandle != IntPtr.Zero)
                CloseHandle(userHandle);
        }
    }
}

ПримерClient.cs

      Impersonation Impersonation = null;
try
{
    Impersonation = new Impersonation(username, null, password);
    LogMsg("Attempting to connect to (" + dbInstance.instance + ")...");
    using (SqlConnection connection = new SqlConnection(connString))
    {
        connection.Open();
        string sql = edtTestSql.Text;
        LogMsg("Attempting to query (" + sql + ")...");
        using (SqlCommand command = new SqlCommand(sql, connection))
        {
            using (SqlDataReader reader = command.ExecuteReader())
            {
                while (reader.Read())
                    LogMsg("next row: " + DumpRow(reader));
            }
        }
    }
}
catch (Exception ex)
{
    LogMsg(ex.Message);
}
finally
{
    if (Impersonation != null)
        Impersonation.Dispose();
}

Неверный логин / пароль также может быть связан с проблемами на вашем DNS-сервере - это то, что случилось со мной и стоило мне 5 часов моей жизни. Смотрите, если вы можете указать IP-адрес вместо имени домена.

Другие вопросы по тегам