Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to make Selenium WebDriver select client certificates dynamically without visually detecting the popup

I'm trying to use Java and Selenium to test a website that requires a client certificate. When I browse to my site I get a popup like the one below to select the correct certificate.

Windows Security: Select a Certificate

My requirements are as follows:

  • Select a certificate by name
  • On different versions of Windows / IE / Edge

Ideally the popup is never shown; i.e., the solution would involve invoking some API or setting some configuration to pin the correct certificate to use.


My own solution ideas:

  • I tried a solution based on visually detecting the correct certificate using SikuliX (which does works) but I'm wondering if there is a better solution that does not rely on visually detecting the popup. Something that is less likely to fail across multiple versions of Windows and that is future proof if Microsoft decides to change the appearance of this popup.

  • Another idea that I had (but I don't know how/if it is possible) is to remove all installed certificates except for one so that the popup is never shown:

    • Backup the entire store
    • Remove all client certificates that IE could use (except the one I need)
    • Do the login which would no longer require any certificate selection
    • Restore the backed up store

    Does anyone know how to do this (in Java, possibly invoking CLI commands)?

  • Is it possible to start (using Selenium Java) an Internet Explorer Window that only knows the single certificate that I need?

  • Is it possible in Internet Explorer to set a default certificate for a given domain?

like image 335
neXus Avatar asked Oct 30 '17 11:10

neXus


People also ask

How does Selenium handle dynamic pop ups?

Handling Web Dialog Box/Popup Window using SeleniumYou can get the window handle of the pop-up window using the WindowHandle() function. I have created my own webpage to demonstrate popup handling in Selenium. You can copy the same code and paste in notepad and save it as html file to proceed with testing.

How you can login into any site if it's showing any authentication popup for password and username?

To handle the basic authentication popup, we can pass the username and password along with the web page's URL. When the login pop-up is prompted, we enter the username as “admin” and the password as “admin” and then login. Thus, the user would be successfully logged into the website.

How will you handle certificates using Selenium?

The answer is simple, on manually opening a URL, the browser automatically imports the required certificates, and no error occurs. Simultaneously, in Selenium WebDriver, each run occurs on a new profile that doesn't have the SSL Certificates, hence the error.


1 Answers

The solution we use is quite clean, easy and portable between browsers and operating systems - use proxy server that will handle SSL handshake for you.

You can set up an in-memory Man-In-The-Middle proxy server in the same JVM the tests is running, or even multiple instances on different ports, each assigned to different client certificate. Then, when creating WebDriver instance, use setProxy method suitable for your browser. Note, the browser will be presented with server certificate that is installed on the proxy itself, not the target server, so there might be some invalid certificate errors that should be suppressed in WebDriver settings. Alternatively - the proxy may simply use valid server certificate, if it's key is available to you, in which case the connection is fully transparent for the test script.

One simple proxy server that offers what is required in Java is LittleProxy. Perhaps something like BrowserMob offers a more complete solution with readily available API.

An example using LittleProxy just needs a few (dozen) lines of boilerplate:

Step 1:
Extend org.littleshoot.proxy.MitmManager class with something you can plugin into your code, making use of client certificates (e.g. p12 files or PEM files). Working example available publicly at this repo.

Step 2:
Start proxy server using client certificate and server certificate of your choice:

org.littleshoot.proxy.impl.DefaultHttpProxyServer.DefaultHttpProxyServer.bootstrap()
        .withIdleConnectionTimeout(FIVE_MINUTES)
        .withName(clientCertFile.getName())
        .withPort(port)
        .withAllowLocalOnly(localConnectionOnly)
        .withManInTheMiddle(new MutualAuthenticationCapableMitmManager(
                usingPKCS12File(clientCertFile, clientCertPassword),
                usingPemKeyPair(serverKeyPair[0], serverKeyPair[1])))
        .start();

Create another proxy for each client certificate you need reusing the same port or by startnig concurrent instances.

Step 3:
Start WebDriver using the proxy. Major browsers (IE, Firefox, Chrome) support the setting in similar fashion:

org.openqa.selenium.Proxy proxy = new Proxy();
proxy.setSslProxy("127.0.0.1:5555");
proxy.setNoProxy("<-loopback>"); // overwrite the default no-proxy for localhost, 127.0.0.1

FirefoxOptions options = new FirefoxOptions();
options.setProxy(proxy);
WebDriver driver = new FirefoxDriver(options);

Step 4:
When running tests, the browser will never bother you with any certificate prompts. Profit.

If using this technique, please be extra carefull to keep the secrets secure and especially the proxy server itself unreachable to third parties. Exposing keys is never good idea outside of secure corporate network, regardless if they are real (!!!) or fake.

like image 158
JockX Avatar answered Oct 06 '22 00:10

JockX