Tuesday, July 30, 2013

Getting cookies from all domains

In automated tests there might be instances where we have to validate cookies of a website.

Webdriver has simple and powerful API to retrieve cookies of current page domain. Here is the sample code to read cookies:

 public Dictionary<string, string> GetAllPageCookies()
        {
            return _driver.Manage().Cookies.AllCookies.ToDictionary(cookie => cookie.Name, cookie => cookie.Value);
        }

The Problem:
However, if a website has some 3rd party plugins such as omniture for page tracking and analysis the cookies are stored under its own domain, not under the domain of your application. By default, as a security measure, browsers don't allow access to cookies from different domain from one domain. Which otherwise will lead to inevitable security issues.

The tricky part is, when you want to validate all the cookies from different domains that are created when a user visits your website.

The Solution:
Solving the problem from webdriver point of view means the feature has to work on all supported  browsers, which is very tough as different browsers implement cookies in different ways. So make it easier I have restricted the solution to Firefox browser which has very good support for plugins and profiles.

To accomplish this task I have created a plugin for firefox called Get all cookies in XML and published it in Mozilla Add-Ons website.

This plugin's job is to use firefox native API to to save all cookies in an XML file under current profile directory of firefox browser.

Once plugin is installed, to capture cookies at any moment open the URL chrome://getAllCookies/content/getAllCookies.xul or click on the menu option which will save all cookies in file by name 'cookie.xml' directly under current profile directory.

The XML schema is as follows:
<cookies>
  <cookie id="cookie_name">
    <host>domain.com</host>
    <isdomain>FALSE</isdomain>
    <path>/</path>
    <issecure>FALSE</issecure>
    <expires>1388032303</expires>
    <name>cookiename</name>
    <value>cookie_value_as_cdata</value>
    <policy>0</policy>
    <status>0</status>
  </cookie>
<cookies>

Cookie.xml is the snapshot of all cookies at a given moment. Having access to this file I can now parse or search for specific cookies using any XML parsing mechanism.

Steps to use this plug-in in your project:
1. Download the plugin from here
2. If you are invoking firefox in specific profile in your automation suite, install the plugin in the same profile
3. If you are not using any specific profile then use AddExtension method of FirefoxProfile class to install plugin at runtime.
4. Assuming firefox is opened wihtout any issues and the browser is navigated to a page where cookies are to be captured, call the following GetAllCookies() method to get XDocumnet object with all cookies.

private XDocument GetAllCookies()
        {
            IJavaScriptExecutor jscript = _driver as IJavaScriptExecutor;
            int lastWindowCount = _driver.WindowHandles.Count;
            if (jscript != null) jscript.ExecuteScript("window.open('')");
            int maxWaitTimeInMilliSeconds = 5000;
            do
            {
                if (lastWindowCount < _driver.WindowHandles.Count)
                    break;

                Thread.Sleep(100);

                maxWaitTimeInMilliSeconds = maxWaitTimeInMilliSeconds - 100;

            } while (maxWaitTimeInMilliSeconds > 0);

            if (maxWaitTimeInMilliSeconds <= 0)
            {
                throw new ApplicationException("Javascript Open Window Failed");
            }

            _driver.SwitchTo().Window(_driver.WindowHandles.Last());
            //Need not open URL; As soon as new window is opened, cookie.xml is re-created with all cookies.
            //If you want to capture cookies without opening a new window, browse to below URL in current window
            _driver.Navigate().GoToUrl("chrome://getAllCookies/content/getAllCookies.xul");
            //Wait for file to get updated
            Thread.Sleep(1000);
            _driver.Close();
            _driver.SwitchTo().Window(_driver.WindowHandles.Last());
            return XDocument.Load(Path.Combine(_ffProfile.ProfileDirectory, "cookie.xml"));
        }

6 comments:

  1. This is so great! Thanks! Have you thought about committing this to selenium?

    ReplyDelete
  2. Hi, this add does not seem to work for MAC. Thanks

    ReplyDelete
  3. Hi, what format is this date 1388032303 ?

    ReplyDelete
  4. Hello there, I was wondering if this plugin can be used in Linux systems?

    ReplyDelete
    Replies
    1. Sorry for the late reply. Yes, where ever firefox browser plugins are supported, this plugin can be used. Let me know if it is not working.

      Delete