Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Add ssl certificate to selenium-webdriver

I use selenium for end-to-end test with chromeDriver. The websites to test require an ssl certificate. When I manually open the browser, there is a popup that lets me select an installed certificate. Different tests access different URLs and also need different certificates. However, if I run the tests in headless mode, there is no popup. So I need a way to programatically set a certificate (eg. set a .pem file) to be used for the current test.

How can I achieve this? I tried setting up a browserMob proxy which I then configured as a proxy in selenium - however, this does not seem to do anything... Are there better approaches? What am I doing wrong? Here's what I tried:

PemFileCertificateSource pemFileCertificateSource = new PemFileCertificateSource(
        new File("myCertificate.pem"),
        new File("myPrivateKey.pem"),
        "myPrivateKeyPassword");

ImpersonatingMitmManager mitmManager = ImpersonatingMitmManager.builder()
        .rootCertificateSource(pemFileCertificateSource)
        .build();

BrowserMobProxy browserMobProxy = new BrowserMobProxyServer();
browserMobProxy.setTrustAllServers(true);
browserMobProxy.setMitmManager(mitmManager);

browserMobProxy.start(8080);


ChromeOptions chromeOptions = new ChromeOptions();
chromeOptions.setProxy(ClientUtil.createSeleniumProxy(browserMobProxy));

WebDriver webDriver = new ChromeDriver(chromeOptions);

// use the webdriver for tests, e.g. assertEquals("foo", webDriver.findElement(...))
like image 230
Patric Avatar asked May 07 '19 06:05

Patric


People also ask

How will you handle SSL certificate in Selenium?

Selenium webdriver is capable of handling SSL certificate in the Safari browser. This is done with the help of the DesiredCapabilities class. We shall create an object of this class. Then apply the setCapability method on it and set the value of property CapabilityType.

How does Selenium handle SSL certificate in Chrome?

We can handle SSL certificate with Selenium webdriver in Chrome browser. A SSL is the standardized protocol used to create a connection between the browser and server. The information exchanged via a SSL certificate is encrypted and it verifies if the information is sent to the correct server.

How do I add an SSL certificate?

In the Websites and Domains section for the domain name you want to use, click SSL/TLS Certificates. Click Add SSL Certificate. Enter a Certificate name, complete the fields in the Settings section, and then click Request. Click the name of the certificate you added to Plesk.


1 Answers

So apparantly this is not possible with BrowserMob out of the box. I therefore wrote a proxy extension SeleniumSslProxy that can be plugged into Selenium and adds certificate based authentication to create a HTTPS connection.

This is how it works:

  • intercept Selenium HTTP requests with BrowserMob
  • setup an SSLContext given a certificate (.pfx file) and password
  • use okhttp to forward the request to the target URL
  • convert the okhttp Response to a netty FullHttpResponse so it can be handled by Selenium

You can find the code on github. Here's an example how it can be used in Selenium end-to-end tests (also works in headless mode):

@Before
public void setup() {
    ClassLoader classLoader = ClassLoader.getSystemClassLoader();
    File clientSslCertificate = new File(
        classLoader.getResource("certificates/some-certificate.pfx").getFile());
    String certificatePassword = "superSecret";

    this.proxy = new SeleniumSslProxy(clientSslCertificate, certificatePassword);
    this.proxy.start();

    ChromeOptions chromeOptions = new ChromeOptions();
    chromeOptions.setProxy(proxy);
    this.webDriver = new ChromeDriver(chromeOptions);
}

@Test
public void pageTitleIsFoo() {
    // given
    String url = "http://myurl.lol";
    // NOTE: do not use https in the URL here. It will be converted to https by the proxy.

    // when
    this.webDriver.get(url);
    this.webDriver.manage().timeouts().implicitlyWait(5, SECONDS);

    // then
    WebElement title = this.webDriver.findElement(By.className("title"));
    assertEquals("Foo", title.getText());
}

@After
public void teardown() {
    this.webDriver.quit();
    this.proxy.stop();
}

Note that I only used chromeDriver and never tested it with other drivers. Minor adjustments to the SeleniumSslProxy might be necessary to be used with other drivers.

like image 119
Patric Avatar answered Sep 20 '22 23:09

Patric