如何正确使用 LogonUser 从工作组客户端模拟域用户

发布于 2024-10-18 04:16:38 字数 1234 浏览 6 评论 0原文

ASP.NET:模拟 VMWare 上的域

这个问题是我要问的,但答案没有提供有关如何派生 _token 的详细信息。它似乎只使用 WindowsIdentity.GetCurrent().Token 因此不会发生假冒行为。

我可以在.NET 中的不同 Active Directory 域?

下一个问题的答案相互矛盾,已接受的答案带有评论“我开始怀疑我的问题出在其他地方”。没有帮助。

LogonUser 仅适用于我的域

下一个问题似乎暗示这是不可能的,但它涉及 2 个域,所以我不确定它是否相关。

我真正的问题是:

  • 可能吗?如果可能的话,
  • 怎么做?我哪里出错了?

到目前为止我尝试过的是,使用 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 错误是

登录失败:用户名未知或密码错误

ASP.NET: Impersonate against a domain on VMWare

This question is what I am asking, but the answer does not provide details on how the _token is derived. It seems to only use WindowsIdentity.GetCurrent().Token so there's no impersonation happening.

Can I impersonate a user on a different Active Directory domain in .NET?

This next question has conflicting answers, with the accepted one bearing a comment "I'm beginning to suspect that my problem lies elsewhere." Not helpful.

LogonUser works only for my domain

This next question seems to imply it is not possible, but it deals with 2 domains so I am not sure if it is relevant.

My real question is:

  • Is it possible? And if so,
  • How? or Where did I go wrong?

What I have tried so far is, using the code from 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

The Win32 error is

Logon failure: unknown user name or bad password

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

失与倦" 2024-10-25 04:16:38

很少有帖子建议使用 LOGON_TYPE_NEW_CREDENTIALS 而不是 LOGON_TYPE_NETWORKLOGON_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 说 < code>LOGON_TYPE_NEW_CREDENTIALS 仅在使用 LOGON32_PROVIDER_WINNT50 时有效。

Very few posts suggest using LOGON_TYPE_NEW_CREDENTIALS instead of LOGON_TYPE_NETWORK or LOGON_TYPE_INTERACTIVE. I had an impersonation issue with one machine connected to a domain and one not, and this fixed it.
The last code snippet in this post suggests that impersonating across a forest does work, but it doesn't specifically say anything about trust being set up. So this may be worth trying:

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 says that LOGON_TYPE_NEW_CREDENTIALS only works when using LOGON32_PROVIDER_WINNT50.

屋檐 2024-10-25 04:16:38

这对我有用,完整的工作示例(我希望更多的人这样做):

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

this works for me, full working example (I wish more people would do this):

//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");
    }
}
近箐 2024-10-25 04:16:38

我也遇到了同样的问题。不知道你是否已经解决了这个问题,但我真正想做的是使用 AD 凭据访问网络共享。在这种情况下,您需要使用 WNetAddConnection2()

I was having the same problem. Don't know if you've solved this or not, but what I was really trying to do was access a network share with AD credentials. WNetAddConnection2() is what you need to use in that case.

不即不离 2024-10-25 04:16:38

我已经成功地模拟了另一个域中的用户,但在两个域之间建立了信任。

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

I have been successfull at impersonating users in another domain, but only with a trust set up between the 2 domains.

var token = IntPtr.Zero;
var result = LogonUser(userID, domain, password, LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, ref token);
if (result)
{
    return WindowsIdentity.Impersonate(token);
}
柠檬心 2024-10-25 04:16:38

最好使用 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);

And:

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

函数定义:

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

It's better to use a 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);

And:

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

Function definition:

private static extern bool LogonUser(
  string pszUserName,
  string pszDomain,
  IntPtr pszPassword,
  int dwLogonType,
  int dwLogonProvider,
  out IntPtr phToken);
落墨 2024-10-25 04:16:38

我遇到的问题是,当我的工作站位于一个域上,但我需要向不同域上的服务器进行身份验证时:

  • 错误:“异常模拟用户,错误代码:1326”
  • 方案:添加了 LOGON32_LOGON_NEW_CREDENTIALS 作为 Impersonate/LogonUser() 的后备

Impersonation.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);
        }
    }
}

ExampleClient.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();
}

The problem I encountered was when my workstation was on one domain, but I needed to authenticate to a server on a different domain:

  • ERROR: "Exception impersonating user, error code: 1326"
  • SOLUTION: Added LOGON32_LOGON_NEW_CREDENTIALS as a fallback to Impersonate/LogonUser()

Impersonation.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);
        }
    }
}

ExampleClient.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();
}
無處可尋 2024-10-25 04:16:38

无效的登录/密码也可能与您的 DNS 服务器中的问题有关 - 这就是发生在我身上的事情,并让我损失了 5 个小时的生命。看看是否可以在域名上指定 IP 地址。

Invalid login/password could be also related to issues in your DNS server - that's what happened to me and cost me good 5 hours of my life. See if you can specify ip address instead on domain name.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文