【问题标题】:IEDriverServer raises error when using impersonation使用模拟时 IEDriverServer 引发错误
【发布时间】:2015-01-30 21:27:24
【问题描述】:

我正在尝试使用模拟测试同时与不同用户连接的 ASP.NET MVC4 Web 应用程序。因此,测试的想法是执行驱动程序的多个实例,每个实例都有不同的模拟用户。这在概念上听起来很简单......

但是,如果在使用与当前用户不同的用户调用 LogonUser 之后运行 IEDriverServer,则在启动时会显示应用程序错误对话框。这是EventLog中注册的信息:

Faulting application name: IEDriverServer.exe, version: 2.44.0.0, time stamp: 0x54496690
Faulting module name: IED7543.tmp, version: 0.0.0.0, time stamp: 0x5449668c
Exception code: 0xc0000005
Fault offset: 0x000000000009d609
Faulting process id: 0x760
Faulting application start time: 0x01d00e3d12f93475
Faulting application path: ...\bin\IEDriverServer.exe
Faulting module path: C:\Users\user\AppData\Local\Temp\IED7543.tmp
Report Id: 5383a54d-7a30-11e4-b39c-000c29b46927

这是我用于模拟的代码。它基于我找到的所有示例,所以我并不感到意外......我们还尝试使用 SimpleImpersonation 包,结果相同:

public class ImpersonationHelper
{
    public enum LogonType
    {
        Interactive = 2,
        Network = 3,
        Batch = 4,
        Service = 5,
        Unlock = 7,
        Cleartext = 8, // Win2K or higher
        NewCredentials = 9 // Win2K or higher
    };

    public enum LogonProvider
    {
        Default = 0,
        Winnt35 = 1,
        Winnt40 = 2,
        Winnt50 = 3
    };

    public enum ImpersonationLevel
    {
        SecurityAnonymous = 0,
        SecurityIdentification = 1,
        SecurityImpersonation = 2,
        SecurityDelegation = 3
    }

    [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
    public static extern bool LogonUser(String lpszUsername, String lpszDomain, String lpszPassword,
        int dwLogonType, int dwLogonProvider, out IntPtr phToken);

    [DllImport("kernel32.dll")]
    [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
    [SuppressUnmanagedCodeSecurity]
    [return: MarshalAs(UnmanagedType.Bool)]
    private static extern bool CloseHandle(IntPtr handle);

    [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    public static extern int DuplicateToken(IntPtr hToken,
        int impersonationLevel, ref IntPtr hNewToken);

    public sealed class Impersonator : IDisposable
    {
        public string Domain { get; private set; }
        public string User { get; private set; }
        public string Password { get; private set; }
        public LogonType Type { get; private set; }
        public LogonProvider Provider { get; private set; }

        private WindowsImpersonationContext _context;
        private IntPtr _token;

        [PermissionSetAttribute(SecurityAction.Demand, Name = "FullTrust")]
        public Impersonator(string domain, string user, string password,
            LogonType type = LogonType.Interactive,
            LogonProvider provider = LogonProvider.Default)
        {
            Domain = domain;
            User = user;
            Password = password;
            Type = type;
            Provider = provider;
            _token = IntPtr.Zero;

            Logon();
        }

        public void Dispose()
        {
            Undo();
        }

        private void Logon()
        {
            try
            {
                if (!LogonUser(User, Domain, Password, (int)Type, (int)Provider, out _token))
                {
                    int ret = Marshal.GetLastWin32Error();
                    throw new Exception(String.Format("LogonUser failed with error code : {0}", ret));
                }

                _context = WindowsIdentity.Impersonate(_token);
            }
            catch (Exception exception)
            {
                var message = exception.Message;
                Undo();
            }
        }

        private void Undo()
        {
            try
            {
                if (_token != IntPtr.Zero)
                {
                    CloseHandle(_token);
                    _token = IntPtr.Zero; // Clean _token so Undo() could be called several times
                }

                if (_context != null)
                {
                    _context.Undo();
                    _context = null; // Clean _context so Undo() could be called several times
                }
            }
            catch (Exception exception)
            {
                var message = exception.Message;
                // Releasing resources failed...
            }
        }
    }
}

引发异常的代码是:

using (new ImpersonationHelper.Impersonator("WIN-NKLTTMMUEPD", "tester", "tester"))
{
    using (IWebDriver driver = new InternetExplorerDriver())
    {
        driver.Url = _appAddress;
        return null;
    }
}

有人知道如何防止出现此错误吗?非常感谢您。

【问题讨论】:

    标签: asp.net-mvc-4 selenium selenium-webdriver impersonation


    【解决方案1】:

    我无法重现您的 IEDriver 崩溃。

    但是,由于您在这个问题上投入了大量资金,我不介意花一点时间来寻找解决方案。我以前从未实现过 Windows 身份验证或需要测试模拟,但是我有 UI 自动化测试的经验。

    时间限制到一个小时:

    • 创建了一个使用 Windows 身份验证的示例 Intranet MVC 应用程序;
    • 添加了一个新项目并设置了一个加载站点的基本单元测试。
    • 添加了模拟。

    我不确定您是如何实现测试的,但是我强烈建议您使用 Seleno 的 .NET/MVC 项目。它是 Selenium Web 驱动程序(您当前使用的)的包装器,但是通过强制实现页面对象和页面组件的约定以及使用强类型视图模型读取和写入网页数据,它使 UI 测试变得不那么痛苦/脆弱。

    我还建议使用 SimpleImpersonation 库,因为它是 Win32 API LogonUser 函数的更安全/更清洁的实现,例如它使用SafeHandle 并且处理路径更干净。

    我写的测试,

    [Test]
    public void GivenImpersonatedUser_IsLoggedInCorrectly()
    {
        const string domain = "domain"; // . for local machine
        const string username = "impersonate.username";
        const string password = "strongp@ssw0rd1";
    
        const LogonType logonType = LogonType.Interactive;
    
        using (Impersonation.LogonUser(domain, username, password, logonType))
        {
            var page = Host.Instance.NavigateToInitialPage<HomePage>();
            Assert.That(page.LoginPanel.LoggedInUserName, Is.EqualTo(string.Format("{0}\\{1}", domain, username)));
        }
    }
    

    这是名为 HomePage 的 Seleno 页面对象,它使用可重用组件 LoginPanel

    public class HomePage : Page
    {
        public LoginPanel LoginPanel
        {
            get { return GetComponent<LoginPanel>(); }
        }
    }
    
    public class LoginPanel : UiComponent
    {
    
        public string LoggedInUserName
        {
            get { return Find.Element(By.Id("login-username")).Text; }
        }
    }
    

    Seleno Host 配置,使用IEDriver

    public static class Host
    {
        private static readonly InternetExplorerDriver Driver = new InternetExplorerDriver();
    
        public static readonly SelenoHost Instance = new SelenoHost();
    
        static Host()
        {
            Instance.Run(c =>
            {
                c.WithRemoteWebDriver(() => Driver);
                c.ProjectToTest(new WebApplication(ProjectLocation.FromFolder("WebApplication1"), 61285));
    
                c.UsingLoggerFactory(new ConsoleFactory());
                c.UsingCamera("C:\\screenshots");
            });
        }
            var codeBase = assembly.CodeBase;
            var uri = new UriBuilder(codeBase);
            var path = Uri.UnescapeDataString(uri.Path);
    
            return Path.GetDirectoryName(path);
        }
    
    }
    

    我学到的其他一些东西: - 如果您的用户名或密码不正确,您将收到错误代码1326。 - 您可以使用Process Hacker 确认使用正确的身份验证令牌启动 webdriver 进程。

    正如我所说,我无法回答您确切的问题,但请尝试使用上述内容并回复评论 - 很乐意为您提供进一步的帮助。

    【讨论】:

    • 您的回答充满了有价值的信息,可以继续研究如何进行涉及多个用户的测试。谢谢你的努力!然而,这个错误原来是关于 x64 版本的驱动程序的问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-03-03
    • 2016-05-24
    • 1970-01-01
    • 2021-04-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多