简体   繁体   English

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

[英]How to use LogonUser properly to impersonate domain user from workgroup client

ASP.NET: Impersonate against a domain on VMWare ASP.NET:模拟 VMWare 上的域

This question is what I am asking, but the answer does not provide details on how the _token is derived.这个问题是我要问的,但答案没有提供有关 _token 是如何派生的详细信息。 It seems to only use WindowsIdentity.GetCurrent().Token so there's no impersonation happening.它似乎只使用WindowsIdentity.GetCurrent().Token所以没有模拟发生。

Can I impersonate a user on a different Active Directory domain in .NET? 我可以在 .NET 中模拟不同 Active Directory 域上的用户吗?

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 LogonUser 仅适用于我的域

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.下一个问题似乎暗示这是不可能的,但它涉及 2 个域,所以我不确定它是否相关。

My real question is:我真正的问题是:

  • Is it possible?是否可以? And if so,如果是这样,
  • How?如何? or Where did I go wrong?或者我go哪里错了?

What I have tried so far is, using the code from http://msdn.microsoft.com/en-us/library/chf6fbt4%28v=VS.80%29.aspx到目前为止我尝试过的是,使用来自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 Win32错误是

Logon failure: unknown user name or bad password登录失败:未知用户名或错误密码

Very few posts suggest using LOGON_TYPE_NEW_CREDENTIALS instead of LOGON_TYPE_NETWORK or LOGON_TYPE_INTERACTIVE . 很少有帖子建议使用LOGON_TYPE_NEW_CREDENTIALS而不是LOGON_TYPE_NETWORKLOGON_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 . MSDN表示 LOGON_TYPE_NEW_CREDENTIALS仅在使用LOGON32_PROVIDER_WINNT50LOGON32_PROVIDER_WINNT50

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

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. 不知道你是否已经解决了这个问题,但我真正想做的是使用AD凭据访问网络共享。 WNetAddConnection2() is what you need to use in that case. 在这种情况下,您需要使用WNetAddConnection2()

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

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. 无效的登录/密码也可能与您的DNS服务器中的问题有关 - 这就是发生在我身上的事情,这让我花了5个小时的时间。 See if you can specify ip address instead on domain name. 看看你是否可以在域名上指定IP地址。

It's better to use a SecureString: 最好使用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);

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"错误: "Exception impersonating user, error code: 1326"
  • SOLUTION: Added LOGON32_LOGON_NEW_CREDENTIALS as a fallback to Impersonate/LogonUser()解决方案:添加LOGON32_LOGON_NEW_CREDENTIALS作为对 Impersonate/LogonUser() 的回退

Impersonation.cs模拟.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 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();
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM