Issue
I have to access a Https API. It works just fine with Postman and with the Android Asynchronous Http Client library.
But when I try it on a desktop java application it just says:
javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
javax.servlet.ServletException: javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target com.sun.jersey.spi.container.servlet.WebComponent.service(WebComponent.java:420) com.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:558) com.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:733) javax.servlet.http.HttpServlet.service(HttpServlet.java:742)
org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
My non-working desktop code:
HttpURLConnection con;
String response;
try {
con = (HttpURLConnection) new URL(LOGIN_URL).openConnection();
con.setDoOutput(true);
con.setRequestMethod("GET");
OutputStream os = con.getOutputStream(); //throws error
os.flush();
return "200";
} catch (Exception e) {
e.printStackTrace();
return e.toString();
}
My Android working code:
AsyncHttpClient client = new AsyncHttpClient();
RequestParams rp = new RequestParams();
client.get("LOGIN_URL", rp, new AsyncHttpResponseHandler() {
@Override
public void onSuccess(int statusCode, Header[] headers, byte[] response) {
return new String(response); //works
}
});
So, my question here is: If it is possible to make it run on Android, why is not working with Apache HttpComponents or the HttpURLConnection methods?
Is there any library I can use without installing any certificates which works just like on Android? I just want to trust the web service without it for several reasons.
Solution
You'll need to add the root chain to your CA certificates file so java can verify the self-signed certificates.
Postman trusts certificates that you have explicitly trusted in your browser.
To update your CA certs file, you'll need to locate it, as you've probably got the JDK installed the one you're looking for will most likely be in the JRE folder of your JDK. ./jdk1.8/jre/lib/security/cacerts
To add a certificate to your trust store use keytool
if java is on your environment path start by running this command where example.der is your certificate. I'd encourage you to give it a better alias name as well.
keytool -import -alias example -keystore /path/to/cacerts -file example.der
You'll be prompted for a password javas default is changeit
enter the password and enter yes
when asked if you trust the certificate.
After adding the certificate you can use keytool again to list all the certificates you have in your keystore, again you'll be prompted for a password.
keytool -list -v -keystore /path/to/cacerts
When I ran this command I was given a list; you should be able to find a certificate with an alias name of example
. This one happened to the be first in my list.
Alias name: digicertglobalrootca [jdk]
Creation date: 26 Aug. 2016
Entry type: trustedCertEntry
Owner: CN=DigiCert Global Root CA, OU=www.digicert.com, O=DigiCert Inc, C=US
Issuer: CN=DigiCert Global Root CA, OU=www.digicert.com, O=DigiCert Inc, C=US
Serial number: 83be056904246b1a1756ac95991c74a
Valid from: Fri Nov 10 10:00:00 AEST 2006 until: Mon Nov 10 10:00:00 AEST 2031
Certificate fingerprints:
SHA1: A8:98:5D:3A:65:E5:E5:C4:B2:D7:D6:6D:40:C6:DD:2F:B1:9C:54:36
SHA256: 43:48:A0:E9:44:4C:78:CB:26:5E:05:8D:5E:89:44:B4:D8:4F:96:62:BD:26:DB:25:7F:89:34:A4:43:C7:01:61
Signature algorithm name: SHA1withRSA
Subject Public Key Algorithm: 2048-bit RSA key
Version: 3
You've updated your question to include that you want to ignore certificates...
Please don't ignore certificate errors. Deal with them instead. Ignoring certificate errors opens the connection to potential MITM attacks. It's tempting to say it's only for test code, it won't end up in production, but we all know what happens when the deadline approaches: the code doesn't show any error when tested -> we can ship it as it is.
Now I know you're determined to do this ANYWAY - so here is some relevant code.
// Create a trust manager that does not validate certificate chains
TrustManager[] trustAllCerts = new TrustManager[]{
new X509TrustManager() {
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
public void checkClientTrusted(
java.security.cert.X509Certificate[] certs, String authType) {
}
public void checkServerTrusted(
java.security.cert.X509Certificate[] certs, String authType) {
}
}
};
// Install the all-trusting trust manager
try {
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, trustAllCerts, new java.security.SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
} catch (Exception e) {
}
// Now you can access an https URL without having the certificate in the truststore
try {
URL url = new URL("https://hostname/index.html");
} catch (MalformedURLException e) {
}
Answered By - Lance
Answer Checked By - Candace Johnson (JavaFixing Volunteer)