Jonathan Gilbert

Automated web testing generally has problems testing sites using Windows Integrated Authentication. This is because the nature of integrated auth is to supply the credentials of the logged-on user - which in the general case is going to be the user running the tests. This may work in some cases, but at the very least it's likely you want to test using both an admin and non-admin user. This can be done with Selenium, but requires some work to get it set up (I'm assuming we're using Selenium Server here).

The goal here is to get the browser running as a specific user (I'm not aware of a way to make the browser authenticate using other credentials). The problem is that your browser is spawned by the Selenium Server, so naturally inherits the logon credentials which started the server. Therefore there are two possible paths to take here - fool Selenium into starting the browser under another user or start Selenium itself under another user. I picked the latter option, although I expect it would be possible to do the former (possibly by replacing the browser executable with a custom script before each test?).

Selenium is fairly quick to start up - certainly in comparison to the speed at which it executes tests, so can be started at the beginning of each test without too much impact on overall testing time. (It would also be possible to maintain state and only respawn if the user changes - but this may not be simple to close on the final test - is there a hook for this?) For our testing (which tests using integrated auth), all Selenium tests create their own Selenium Server instance in a SetUp() method from a base test class (note that the tests are C#/NUnit), and close it in the TearDown() method. The C# code is below which uses the .NET API to start the process under another user - this would be marginally more complex in Java, but could be achieved by invoking the runas command to spawn Selenium.



public class SeleniumContainer
{
 private readonly Process process = new Process();
 private bool started;
 
 public SeleniumContainer(bool asAdmin)
 {
  process.StartInfo.FileName = "java";
  process.StartInfo.Arguments = "-jar lib/selenium-server.jar";
  process.StartInfo.CreateNoWindow = false;
  process.StartInfo.WindowStyle = ProcessWindowStyle.Normal;
  process.StartInfo.UseShellExecute = false;
  string[] domainAndUser = Config[asAdmin ? ConfigProps.AdminUser : ConfigProps.NonAdminUser].Split('\\');
  string password = Config[asAdmin ? ConfigProps.AdminPassword : ConfigProps.NonAdminPassword];
  
  process.StartInfo.UserName = domainAndUser[1];
  
  SecureString pw = new SecureString();
  
  foreach (char c in password)
  pw.AppendChar(c);
  
  process.StartInfo.Password = pw;
  
  DirectoryInfo currentDir = new DirectoryInfo(Environment.CurrentDirectory);
  
  process.StartInfo.WorkingDirectory = currentDir.Parent.Parent.Parent.Parent.FullName;
  
  if (Config.Exists(ConfigProps.SeleniumFirefoxProfile))
  {
   process.StartInfo.Arguments += (" -firefoxProfileTemplate " + Config[ConfigProps.SeleniumFirefoxProfile]);
  }
 }
 
 public void Start()
 {
  lock (this)
  {
   if (started)
   throw new InvalidOperationException("Selenium already started");
   if (!process.Start())
   throw new Exception("Failed to start Selenium process");
   
   started = true;
  }
  
  //give it half a second to start up
  Thread.Sleep(500);
 }
 
 public void Stop()
 {
  lock (this)
  {
   if (!started)
   throw new InvalidOperationException("Selenium not running");
   
   try
   {
    process.CloseMainWindow();
   }
   catch
   {
    //Ignore
   }
   
   //give Selenium 5sec to close before we kill it
   if (!process.WaitForExit(5000))
   process.Kill();
   
   started = false;
  }
 }
}




Testing using Firefox

Firefox in general does not send integrated auth credentials, but can be told to. To do this go to the firefox about:config screen and search for ntlm - there should be three options, two of which need changing.
network.ntlm.send-lm-response: enable this (set to true)
network.automatic-ntlm-auth.trusted-uris: set this to a string representing your host (it's a URL pattern)
Once this is working for firefox you will need to save the profile directory and pass it to Selenium when it starts so that it can use your modified firefox profile (by default it uses it's own). This is done using the -firefoxProfileTemplate parameter, as you can see in the above code. Oh, and you'll need at least version 1.0-beta-2 of Selenium if you want to use firefox 3.

2 Comment(s)

Which versions of windows have you tried this on? I've seen people having problems starting the server on Vista and 2k8 as users which do not have admin rights to the machine. That might skew your resulting behavior.

-adam

By Adam Goucher at June 12, 2009 7:23 PM

I have been running this on XP - I can't comment on Vista/2k8, but it wouldn't surprise me if using these as a non-admin user caused issues. You'd probably need the Windows security privilege to impersonate another user for this to work (I don't know if this is granted by default to non-admins). As you say there may also be issues for the server as it needs to listen on a port - this would require opening a firewall port which would probably be impossible for non-admins. I expect it would be possible to get this to work, but would certainly require some security modifications.

By Jonathan Gilbert at June 14, 2009 6:46 PM

Post a comment

If you haven't left a comment here before, you may need to be approved by the site owner before your comment will appear. Until then, it won't appear on the entry. Thanks for waiting.





Remember personal info?

Type the characters you see in the picture above.