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

时间:2011-02-16 23:48:03

标签: c# .net winforms c#-2.0 impersonation

ASP.NET: Impersonate against a domain on VMWare

这个问题就是我要问的问题,但答案并未提供有关_token如何派生的详细信息。它似乎只使用WindowsIdentity.GetCurrent().Token所以没有模仿发生。

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

下一个问题的答案相互矛盾,接受的答案是“我开始怀疑我的问题出在其他地方。”没用。

LogonUser works only for my domain

下一个问题似乎暗示这是不可能的,但它涉及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错误是

  

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

6 个答案:

答案 0 :(得分:55)

很少有帖子建议使用LOGON_TYPE_NEW_CREDENTIALS代替LOGON_TYPE_NETWORKLOGON_TYPE_INTERACTIVE。我有一个假冒问题,一台机器连接到一个域而一个没有,这就解决了。 this post中的最后一个代码段表明模仿森林确实有效,但它没有具体说明建立信任的任何内容。所以这可能值得尝试:

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 LOGON_TYPE_NEW_CREDENTIALS仅在使用LOGON32_PROVIDER_WINNT50时才有效。

答案 1 :(得分:18)

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

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

答案 2 :(得分:1)

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

答案 3 :(得分:1)

我在模拟其他域中的用户方面取得了成功,但且在两个域之间设置了信任。

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

答案 4 :(得分:0)

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

答案 5 :(得分:0)

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