Handling SSL Certificates


How to handle SSL Certificates ..??

This Exception may be common to all , but my fingers crossed when I see the next wizard, as shown in second image, 

Image 1:  This Connection is Untrusted
If we click 'Add Exception' button in the first page, then the next wizard comes up as shown below

Image 2: Add Security Exception

After a long search on some forums, I found that a small piece of code are not explained by most of the them or may be I come across most of such blogs. However, I thought of to put what I have discovered and handled this issue and where I was missing or may be you are missing the actual explanation in other blogs

Apparently, handling this ssl certificate can be achieved on firefox browser only, because it allows users to access the profile and where as other browsers doesn't have option for creating custom browser profile, if any one knows, please let me know in comments

Now, before explaining code, I want to explain how to create custom firefox profile then the code might be easily understands at its a very few in lines. 

How to create custom firefox profile?

1) Close all firefox browser windows and run the following command
firefox -ProfileManager -no-remote
2) Click "Create Profile"  and follow the instructions on the wizard
3) You can create with any name, as I created with "QAAutomation" as shown in below image

"firefox -ProfileManager -no-remote" to choose firefox profile

This is how we can create profiles in firefox browser, now we have to use this profile in our selenium webdirver code, as follows

#Java Program:

Method 1:
/**
 * Handle Untrusted HTTPs Connections With Selenium web driver. Also, handle an
 * additional wizards like, 'Add Security Exception' by Confirm Security
 * Exception
 * 
 * @author Fayaz
 * 
 */
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.firefox.FirefoxProfile;
import org.openqa.selenium.firefox.internal.ProfilesIni;


public class HandleWindows {

public static void main(String[] args){
ProfilesIni profile = new ProfilesIni();
FirefoxProfile ffProfile = profile.getProfile("QAAutomation"); // firefox profile **
ffProfile.setAcceptUntrustedCertificates(true);
ffProfile.setAssumeUntrustedCertificateIssuer(false);
WebDriver driver = new FirefoxDriver(ffProfile);
driver.get(URL);
}
}


** Most of the blogs are pasted code as it is, where some says, "HandleSSLCertificate" but they don't explain what is this "HandleSSLCertificate", whereas others explains simply as "firefox user profile name" (but they missed how to create profile, indeed)


Remember most of us use "default" as a profile name, by default. So please pass "default" as an parameter to getProfile() and try if you want, that is new ProfilesIni().getProfile("default");

Method 2:

/**
 * Handle Untrusted HTTPs Connections With Selenium web driver. Also, handle an
 * additional wizards like, 'Add Security Exception' by Confirm Security
 * Exception
 *
 * @author Fayaz
 *
 */
import java.io.File;

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.firefox.FirefoxProfile;
import org.openqa.selenium.firefox.internal.ProfilesIni;


public class HandleWindows {

 public static void main(String[] args){
 FirefoxProfile ffProfile = new FirefoxProfile(new File("C:\\Users\\Fayaz\\Desktop\\Selenium\\custom")); // firefox profile**
  ffProfile.setAcceptUntrustedCertificates(true);
  ffProfile.setAssumeUntrustedCertificateIssuer(false);
  WebDriver driver = new FirefoxDriver(ffProfile);
  driver.get(URL);

 }
}

** While creating a firefox profile I created a new folder with name 'custom'. That is though "QAAutomation" is actual firefox profile name, it is created under 'custom' directory. so custom is a my favorite directory on my machine where as QAAutomation is a firefox profile name


Finally, those who wants to execute test from command line interface aka CLI, then the command should be like, 
java -jar selenium-server.jar -firefoxProfileTemplate "C:\Users\Fayaz\Desktop\Selenium",
instead  of the giving the whole default path like, 
java -jar selenium-server.jar -firefoxProfileTemplate "C:\Documents and Settings\Fayaz\Application Data\Mozilla\Firefox\Profiles\io4kgk8d.default"
That's all we are done. For more info see Tips & Tricks page

Chrome :

Though by the time of writing this blog page, I didn't find the similar way, how we are handling dialog firefox browser. However, one way I used to handle this certificate dialog while using chrome is using Threads in java

Before, you read further, let me tell you what my issue was

When I request to an URL by calling our selenium WebDrivers, get(String URL) method and before the response gets back, certificate dialog is appearing and until I select the certificate the URL page isn't loading.
System.setProperty("webdriver.chrome.driver", "C:\\Users\\Fayaz\\Desktop\\chromedriver.exe");
WebDriver driver = new ChromeDriver(); 
driver.get(URL); // this method execution is not finishing until I select a dialog in the //certificate dialog
driver.findElements(By.cssSelector("input#username")); //this code is not at all reaching

 So, inorder to handle this, what I did was, I was calling a Thread in which using Robot class, making enter key to press. That is, start a thread and make it to sleep for a while then do request to URL from driver.get() method, by the time certificate dialog appears our Thread process should finishes its sleep time and then start the thread to run, where in run() method, our Robot class hit the enter button

Here is the working code for me, how it works....        

#Java Program:

package selenium.project;

import java.awt.AWTException;
import java.awt.Robot;
import java.awt.event.KeyEvent;

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import org.openqa.selenium.remote.CapabilityType;
import org.openqa.selenium.remote.DesiredCapabilities;

/**
 * Handle Untrusted HTTPs Connections With Selenium web driver. Also, handle an
 * additional wizards like, 'Add Security Exception' by Confirm Security
 * Exception
 *
 * @author Fayaz
 *
 */
public class HandleWindows {

private static final String URL = "<your URL here> ";

public static void main(String[] args) {
WebDriver driver = null;
try {
System.setProperty("webdriver.chrome.driver", "C:\\Users\\Fayaz\\Downloads\\chromedriver.exe");
driver = new ChromeDriver();
Thread certSelectionThread = null;
Runnable r = new Runnable() {

@Override
public void run() {
try {
Thread.sleep(1000 * 10);
Robot robot = new Robot();
robot.keyPress(KeyEvent.VK_ENTER);
} catch (AWTException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
certSelectionThread = new Thread(r);
certSelectionThread.start();
driver.get(URL);
if(certSelectionThread != null){
try {
certSelectionThread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} finally {
if(driver != null && !driver.toString().contains("null")){
driver.close();
driver.quit();
}
}
}
}



Sometime we need to handle certificate issues (SSL) with chrome as well especially for self-signed certificates. else we get exception, which says as follows

javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed:
sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:387)
at sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:292)
at sun.security.validator.Validator.validate(Validator.java:260)
at sun.security.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:324)
at sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:229)
at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:124)
at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1351)
at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:156)
at sun.security.ssl.Handshaker.processLoop(Handshaker.java:925)
at sun.security.ssl.Handshaker.process_record(Handshaker.java:860)
at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1043)
at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1343)
at sun.security.ssl.SSLSocketImpl.writeRecord(SSLSocketImpl.java:728)
at sun.security.ssl.AppOutputStream.write(AppOutputStream.java:123)
at sun.security.ssl.AppOutputStream.write(AppOutputStream.java:138)



when we run the following piece of code

public static boolean waitUntilRequestCompletes(String urlRequest) {
try {
URL url = new URL(urlRequest);
HttpURLConnection conn;
conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setRequestProperty("Accept", "application/json");

if (conn.getResponseCode() != 200) {
throw new RuntimeException(" HTTP error code : "
+ conn.getResponseCode());
}

Scanner scan = new Scanner(url.openStream());
String entireResponse = new String();
while (scan.hasNext()) {
entireResponse += scan.nextLine();
System.out.println("Response : " + entireResponse);
}
scan.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return false;
}


To avoid such exception it is important to add signed certificate to JVM - security\cacerts.

How to do that.?

So from the insecure URL download the certificate, follow this page to know how to download certificate

Once the certificate in place, open command prompt in admin mode and run the following command

keytool -import -alias example_name -keystore "C:\Program Files\Java\jdk1.8.0_121\jre\lib\security\cacerts" -file "C:\Users\Fayaz\Desktop\ss_certificate\pd-123456789.cer"

That's it done. happy secure connection :)

1 comment:

  1. Hi Fayaz, did you find any workaround to handle download dialogs in chrome using selenium webdriver.?

    ReplyDelete