Automating the “Windows Security” Dialog with UIAutomation

I decided to finally learn some Selenium in order to test an internal Line of Business (LOB) web application. After a quick crash course on Selenium automation, I got a prototype for my test initialization working, but quickly hit this:

image

I was a bit miffed to learn that Selenium does not natively handle the authentication dialog. Bummer. After fighting with UIAutomation for several hours, here’s a solution I came up with. Hopefully this will save some other people time.

// Add references to the following assemblies:
// System.Windows.Forms
// UIAutomationClient
// UIAutomationTypes
using System.Windows.Automation;
using System.Windows.Forms;
// Portions of code adapted from http://www.mathpirate.net/log/2009/09/27/swa-straight-outta-redmond/
public static void HandleAuthenticationDialogForIE(string userName, string password)
{
if(String.IsNullOrWhiteSpace(userName))
{
throw new ArgumentNullException(userName, "Must contain a value");
}
if(String.IsNullOrWhiteSpace(password))
{
throw new ArgumentNullException(password, "Must contain a value");
}
// Condition for finding all "pane" elements
Condition paneCondition = new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Pane);
// Conditions for finding windows with a class of type dialog that's labeled Windows Security
Condition windowsSecurityCondition = new AndCondition(
new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Window),
new PropertyCondition(AutomationElement.ClassNameProperty, "#32770"),
new PropertyCondition(AutomationElement.NameProperty, "Windows Security"));
// Conditions for finding list elements with an AutomationId of "UserList"
Condition userListCondition = new AndCondition(
new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.List),
new PropertyCondition(AutomationElement.AutomationIdProperty, "UserList"));
// Conditions for finding the account listitem element
Condition userTileCondition = new AndCondition(
new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.ListItem),
new PropertyCondition(AutomationElement.ClassNameProperty, "CredProvUserTile"),
new PropertyCondition(AutomationElement.NameProperty, "Use another account"));
// Conditions for finding the OK button
Condition submitButtonCondition = new AndCondition(
new PropertyCondition(AutomationElement.IsEnabledProperty, true),
new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Button),
new PropertyCondition(AutomationElement.AutomationIdProperty, "SubmitButton"));
// Conditions for finding the edit controls
Condition editCondition = new AndCondition(
new PropertyCondition(AutomationElement.IsEnabledProperty, true),
new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Edit));
Console.Write("Looking for credentials dialog…");
// Find all "pane" elements that are children of the desktop
AutomationElementCollection panes = AutomationElement.RootElement.FindAll(TreeScope.Children, paneCondition);
bool foundSecurityDialog = false;
// Iterate through the collection of "panes"
foreach(AutomationElement pane in panes)
{
// Check to see if the current pane is labeled as IE
if(pane.Current.Name.Contains("Windows Internet Explorer"))
{
// Ok, we found IE. Now find all children of the IE pane that meets the windowSecurityCondition defined above
AutomationElement windowsSecurityDialog = pane.FindFirst(TreeScope.Children, windowsSecurityCondition);
if (windowsSecurityDialog != null)
{
// Great, we found the dialog
Console.WriteLine("found security dialog");
foundSecurityDialog = true;
// Grab the first child of the dialog that is a UserList
AutomationElement userList = windowsSecurityDialog.FindFirst(TreeScope.Children, userListCondition);
// Grab the first child of the UserList that is a UserTile
AutomationElement userTile = userList.FindFirst(TreeScope.Children, userTileCondition);
// Make sure the UserTile has focus so that we can see the UserName and Password edit boxes
userTile.SetFocus();
// Get all children of the UserTile that are edit controls
AutomationElementCollection edits = userTile.FindAll(TreeScope.Children, editCondition);
// Iterate thru the edit controls
foreach(AutomationElement edit in edits)
{
if(edit.Current.AutomationId == "CredProvClearTextEdit")
{
// We found the username edit control. Let's set the contents of the box to the username.
Console.WriteLine("Entering username");
ValuePattern userNamePattern = (ValuePattern)edit.GetCurrentPattern(ValuePattern.Pattern);
userNamePattern.SetValue(userName);
}
if(edit.Current.AutomationId == "CredProvPasswordEdit")
{
// We found the password edit control. Let's set the contents of the box to the password.
Console.WriteLine("Entering password");
ValuePattern userNamePattern = (ValuePattern)edit.GetCurrentPattern(ValuePattern.Pattern);
userNamePattern.SetValue(password);
}
}
// Find the first child of the security dialog that meets the submitButtonCondition defined above
AutomationElement submitButton = windowsSecurityDialog.FindFirst(TreeScope.Children, submitButtonCondition);
// Now press the button
InvokePattern buttonPattern = (InvokePattern)submitButton.GetCurrentPattern(InvokePattern.Pattern);
buttonPattern.Invoke();
break;
}
}
}
if(!foundSecurityDialog)
{
Console.WriteLine("no security dialogs found.");
}
}

Note that this code only works with IE. WebKit browsers implement the authentication dialog in their own funky ways. But for my purposes, our LOB app is IE based only. #winning

This entry was posted in testing, Work and tagged , , , , , . Bookmark the permalink.

9 Responses to Automating the “Windows Security” Dialog with UIAutomation

  1. Ven says:

    Hey, This is exactly what I’ve been looking for, but when I seem to run it on IE, the code breaks when it reaches
    AutomationElement userList = windowsSecurityDialog.FindFirst(TreeScope.Children, userListCondition);
    and gives me a null value, I’m not entirely sure why, but I was also wondering where did you obtain these parameters from?

    • Ven says:

      Sorry, it retrieves a null value and breaks on AutomationElement userTile = userList.FindFirst(TreeScope.Children, userTileCondition); where userList == null

      And I’m not sure if the same conditions apply for my case because I am trying to access a server website…

  2. Pingback: Using UISpy to Handle the Windows Security Dialog in Windows 7 | Nithin's Blog

  3. Ven says:

    Great tutorial, but I eventually changed the configuration settings on my server that I’m accessing and completely removed the windows authentication and simply used IP filtering/restriction for the server in IIS manager. In my case, the security dialog box was not necessary since it was only being used for testing purposes, but once again, thank you for looking into this!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s