【问题标题】:Impersonation works locally, fails on server模拟在本地工作,在服务器上失败
【发布时间】:2015-04-01 04:29:28
【问题描述】:

自助服务密码重置网站。对于某些操作,我冒充在域中具有帐户操作员权限的技术用户。它可以在我的笔记本电脑上完美运行,我可以更改用户密码、解锁帐户或查询所有锁定帐户的域。

直到大约 2 周前,它甚至还可以在服务器上运行。我试图调查我们的环境机器人的变化,没有人知道任何可能对此产生影响的变化。

最好的部分是我根本没有错误消息。 Marshal.GetLastWin32Error() 返回零,基本上是“一切正常”。

这是发生模拟的代码:

    #region accountManagement

    [DllImport("advapi32.dll")]
    public static extern int LogonUserA(String lpszUserName, String lpszDomain, String lpszPassword, int dwLogonType, int dwLogonProvider, ref IntPtr phToken);
    [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    public static extern int DuplicateToken(IntPtr hToken, int impersonationLevel, ref IntPtr hNewToken);
    [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    public static extern bool RevertToSelf();
    [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
    public static extern bool CloseHandle(IntPtr handle);

    WindowsImpersonationContext impersonationContext;

    private bool impersonateValidUser(String userName, String domain, String password)
    {
        const int LOGON32_LOGON_INTERACTIVE = 2;
        const int LOGON32_LOGON_NETWORK = 3;
        const int LOGON32_LOGON_BATCH = 4;
        const int LOGON32_LOGON_SERVICE = 5;
        const int LOGON32_LOGON_UNLOCK = 7;
        const int LOGON32_LOGON_NETWORK_CLEARTEXT = 8;
        const int LOGON32_LOGON_NEW_CREDENTIALS = 9;
        const int LOGON32_PROVIDER_DEFAULT = 0;

        WindowsIdentity tempWindowsIdentity;
        IntPtr token = IntPtr.Zero;
        IntPtr tokenDuplicate = IntPtr.Zero;

        if (RevertToSelf())
        {
            // Int32 result = LogonUserA(userName, domain, password, LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, ref token);
            // Response.Write(">>> " + result.ToString());
            if (LogonUserA(userName, domain, password, LOGON32_LOGON_UNLOCK, LOGON32_PROVIDER_DEFAULT, ref token) != 0)
            {
                if (DuplicateToken(token, 2, ref tokenDuplicate) != 0)
                {
                    tempWindowsIdentity = new WindowsIdentity(tokenDuplicate);
                    impersonationContext = tempWindowsIdentity.Impersonate();
                    if (impersonationContext != null)
                    {
                        CloseHandle(token);
                        CloseHandle(tokenDuplicate);
                        return true;
                    }
                }
            }
        }

        if (token != IntPtr.Zero)
            CloseHandle(token);
        if (tokenDuplicate != IntPtr.Zero)
            CloseHandle(tokenDuplicate);
        return false;
    }

    private void undoImpersonation()
    {
        impersonationContext.Undo();
    }

    #endregion

这就是它的名字(不相关的部分被删除):

                String iuUser = System.Configuration.ConfigurationManager.AppSettings["domain.accountop.user"];
                String iuPass = System.Configuration.ConfigurationManager.AppSettings["domain.accountop.pass"];
                String iuDomn = System.Configuration.ConfigurationManager.AppSettings["domain.name"];
                if (impersonateValidUser(iuUser, iuDomn, iuPass))
                {
                    try
                    {
                        email = user.Properties["mail"].Value.ToString();
                        user.Invoke("SetPassword", new object[] { pw1 });
                        user.Properties["LockOutTime"].Value = 0; //unlock account
                        user.CommitChanges();
                        user.Close();

                        undoImpersonation();

                        // clear form and redirect
                        pPopupSuccess.Visible = true;
                        hfSuccess.Value = "The account is unlocked now and the password has been reset successfully.";
                    }
                    catch (Exception ex)
                    {
                        Exception innerException = ex.InnerException;
                        DirectoryServicesCOMException exds = (DirectoryServicesCOMException)innerException;
                        String errorMessage = "<p><strong>Your password probably did not meet the requirements.</strong></p>";
                        errorMessage += "<p>" + System.Configuration.ConfigurationManager.AppSettings["domain.pwreqmessage"] + "</p>";
                        errorMessage += "<strong>Detailed error message:</strong><br />";
                        errorMessage += ex.Message;
                        errorMessage += "<br />";
                        errorMessage += ex.StackTrace;

                        if (innerException != null) { 
                            errorMessage = errorMessage + innerException.Message;
                        }
                        pPopupError.Visible = true;
                        hfErrorMessage.Value = errorMessage;
                    }
                }
                else
                {
                    // The impersonation failed. Include a fail-safe mechanism here.
                    pPopupError.Visible = true;
                    hfErrorMessage.Value = "<p>Impersonation error. Failed to elevate the rights to account operator. Please report this error to the Help Desk.</p>";
                    hfErrorMessage.Value += "<p>" + Marshal.GetLastWin32Error().ToString() + "</p>";
                }

我一直得到的不是中间的异常,而是我自己在第二个代码段末尾的消息说模拟不成功。而 Marshal.GetLastWin32Error() 只是返回零。

这里可能出了什么问题,我如何才能获得有关正在发生的事情的更多信息?在我的开发 PC 上运行正常时,导致此代码失败的服务器上有什么不同?

【问题讨论】:

  • 附加信息:我的笔记本电脑和服务器都不是我现在正在开发/测试的域的成员。但是这些域是受信任的。

标签: c# asp.net active-directory impersonation


【解决方案1】:

抱歉,这是#PEBKAC。 Windows 安全日志提示

此时尚未授予用户请求的登录类型 机器。

所以答案是“检查你的 Windows 事件!”

这很奇怪,因为我一直在用这个技术帐户使用这个服务器。所以我仔细检查了用户并将其放回服务器的Administrators组。我认为这超出了我的实际需要,也是一个安全风险,但我很快会做一些实验,看看在本地保持它工作的最低权限是多少。

【讨论】:

  • @Moderators:也许我们应该删除这个问题?
猜你喜欢
  • 2023-03-17
  • 1970-01-01
  • 1970-01-01
  • 2016-11-01
  • 2020-12-02
  • 2019-06-08
  • 1970-01-01
  • 1970-01-01
  • 2021-04-21
相关资源
最近更新 更多