模拟在本地工作,在服务器上失败

时间:2015-02-02 09:04:49

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

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

直到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上运行正常?

1 个答案:

答案 0 :(得分:0)

抱歉,这是#PEBKAC。 Windows安全日志建议

  

此处未向用户授予请求的登录类型   机。

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

这很奇怪,因为我一直在使用这个技术帐户的服务器。所以我仔细检查了用户并将其放回服务器的Administrators组。我认为这不仅仅是我真正需要的,也是一种安全风险,但我会尽快做一些实验,看看本地最低限度的权利是什么让它保持运作。