我有一个ASP.NET MVC网站使用
Windows身份验证来控制访问.我想要有一个specflow selenium测试,通过尝试作为非授权用户访问该站点来检查配置是否正确.
当我们使用域帐户来控制访问时,没有用户名/密码登录屏幕.当前用户的凭据由浏览器自动传递到该站点.
所以对于我的Selenium测试,我需要能够以特定的用户身份运行Internet Explorer.
我发现了一些关于Windows模拟的文章,我可以在测试运行期间切换到我的测试用户(使用http://support.microsoft.com/kb/306158的代码).但是,如果我创建一个InternetExplorerDriver它启动Internet Explorer与我的凭据,而不是测试用户(虽然这个问题和答案表明它应该工作https://sqa.stackexchange.com/questions/2277/using-selenium-webdriver-with-windows-authentication).
我也可以显式地启动Internet Explorer进程作为我的测试用户,但是我看不到将InternetExplorerDriver绑定到已经运行的Internet Explorer进程的方式,所以这可能是一个死胡同.
我的代码,基本上是从上面的MSDN页面下面的.在调试器中,我可以看到WindowsIdentity.GetCurrent().Name在测试的所有步骤中都是“testUser”.
namespace MyProject.Specs { using NUnit.Framework; using OpenQA.Selenium; using OpenQA.Selenium.IE; using System; using System.Runtime.InteropServices; using System.Security.Principal; using TechTalk.SpecFlow; [Binding] public class AuthorisationSteps { public const int logoN32_logoN_INTERACTIVE = 2; public const int logoN32_PROVIDER_DEFAULT = 0; private static WindowsImpersonationContext impersonationContext; private static IWebDriver driver; [BeforeScenario] public static void impersonateUser() { if (!impersonateValidUser("testUser","testDomain","password")) { throw new Exception(); } driver = new InternetExplorerDriver(); } [AfterScenario] public static void cleanupUser() { undoImpersonation(); driver.Quit(); } [Given(@"I am an unauthorised user")] public void GivenIAmAnUnauthorisedUser() { var temp = WindowsIdentity.GetCurrent().Name; } [When(@"I go to the home page")] public void WhenIGoToTheHomePage() { var temp = WindowsIdentity.GetCurrent().Name; driver.Navigate().GoToUrl(BaseUrl); } [Then(@"I should see an error page")] public void ThenIShouldSeeAnErrorPage() { var temp = WindowsIdentity.GetCurrent().Name; Assert.That(driver.Title.Contains("Error")); } [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",SetLastError = true)] public static extern bool RevertToSelf(); [DllImport("kernel32.dll",CharSet = CharSet.Auto)] public static extern bool CloseHandle(IntPtr handle); private static bool impersonateValidUser(String userName,String domain,String password) { WindowsIdentity tempWindowsIdentity; var token = IntPtr.Zero; var tokenDuplicate = IntPtr.Zero; if (RevertToSelf()) { if (logonUserA(userName,domain,password,logoN32_logoN_INTERACTIVE,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 static void undoImpersonation() { impersonationContext.Undo(); } }
}
解决方法
这实际上是可行的.我遇到了你所拥有的确切问题.基本上,这里是您需要做的步骤.
Process driverProcess; string driverPath; // The path to Selenium's IE driver. ProcessStartInfo info = new ProcessStartInfo(driverPath) { UserName = "UserName",// The user name. Password = new SecureString(),// The password for the user. UseShellExecute = false,LoadUserProfile = true,Arguments = "about:blank" }; // Start the driver in background thread Thread startThread = new Thread( () => { try { driverProcess = Process.Start(info); driverProcess.WaitForExit(); } catch { // Close the process. } }) { IsBackground = true }; startThread.Start();
>使用远程Web驱动程序来连接手动启动的浏览器驱动程序实例.
var remoteDriver = new RemoteWebDriver(Uri("http://localhost:5555"),DesiredCapabilities.InternetExplorer());
// Close the process when done. if (driverProcess != null) { // Free managed resources if (!driverProcess.HasExited) { driverProcess.CloseMainWindow(); driverProcess.WaitForExit(5000); // Kill the process if the process still alive after the wait if (!driverProcess.HasExited) { driverProcess.Kill(); } driverProcess.Close(); } driverProcess.Dispose(); driverProcess = null; }