Reputation: 359
I have a web app (on WebSphere) that interacts with 3rd party to format some received data, and then make RESTful call to said 3rd party, which resides on a Tomcat server
. Within the web app I can successfully make a basic RESTful GET
call using Java's native HttpsUrlConnection
(see below), but when I use Apache's HttpClient
, it fails with an SSL
chaining error.
The HttpsURLConnection:
String urlWithParams = "https://example.com/rest/issue/59";
String methodType = "GET";
String acceptType = MediaType.APPLICATION_JSON;
HttpsURLConnection conn = null;
try {
URL url = new URL(urlWithParams);
conn = (HttpsURLConnection) url.openConnection();
conn.setRequestMethod(methodType);
conn.setRequestProperty("Accept", acceptType);
if (conn.getResponseCode() != 200) {
System.out.println("Failed. httpErrorUrl=" + conn.getResponseCode()
+ " httpErrorCode=" + conn.getResponseCode()
+ " httpErrorMsg=" + conn.getResponseMessage());
}
BufferedReader br = new BufferedReader(new InputStreamReader((conn.getInputStream())));
String rawData;
String toReturn = "";
while ((rawData = br.readLine()) != null) {
toReturn += rawData;
}
System.out.println(toReturn);
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally{
if(conn != null){
conn.disconnect();
} else {
System.out.println("httpUrlConnection is null");
}
}
The HttpClient code:
String uri = "https://example.com/rest/issue/59";
PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager();
connManager.setDefaultMaxPerRoute(20);
connManager.setMaxTotal(40);
CloseableHttpClient httpclient = HttpClients.createDefault();
The HttpClient methods are executed in the function below:
private JSON request(HttpRequestBase req) throws RestException, IOException {
req.addHeader("Accept", "application/json");
if (creds != null)
creds.authenticate(req);
HttpResponse resp = httpClient.execute(req);
HttpEntity ent = resp.getEntity();
StringBuilder result = new StringBuilder();
if (ent != null) {
String encoding = null;
if (ent.getContentEncoding() != null) {
encoding = ent.getContentEncoding().getValue();
}
if (encoding == null) {
Header contentTypeHeader = resp.getFirstHeader("Content-Type");
HeaderElement[] contentTypeElements = contentTypeHeader.getElements();
for (HeaderElement he : contentTypeElements) {
NameValuePair nvp = he.getParameterByName("charset");
if (nvp != null) {
encoding = nvp.getValue();
}
}
}
InputStreamReader isr = encoding != null ?
new InputStreamReader(ent.getContent(), encoding) :
new InputStreamReader(ent.getContent());
BufferedReader br = new BufferedReader(isr);
String line = "";
while ((line = br.readLine()) != null)
result.append(line);
}
StatusLine sl = resp.getStatusLine();
if (sl.getStatusCode() >= 300)
throw new RestException(sl.getReasonPhrase(), sl.getStatusCode(), result.toString());
return result.length() > 0 ? JSONSerializer.toJSON(result.toString()): null;
}
The error produced is a typical chaining exception, which usually means the SSL
certs are not correct. Since the certs are imported at the App Server level, I would expect the SSL
connections to be handled the same for both HttpsURLConnection
and HttpClient
calls.
Caused by: `com.ibm.jsse2.util.j: PKIX` path building failed: `java.security.cert.CertPathBuilderException: PKIXCertPathBuilderImpl` co
uld not build a valid CertPath.;
internal cause is:
java.security.cert.CertPathValidatorException:
The certificate issued by CN=Entrust Root Certification Authority, OU="(c) 2
006 Entrust, Inc.", OU=www.entrust.net/CPS is incorporated by reference, O="Entrust, Inc.", C=US is not trusted; internal cause is:
`java.security.cert.CertPathValidatorException:` Certificate chaining error
at com.ibm.jsse2.util.h.b(h.java:18) ~[na:6.0 build_20141024]
at com.ibm.jsse2.util.h.b(h.java:118) ~[na:6.0 build_20141024]
at com.ibm.jsse2.util.g.a(g.java:14) ~[na:6.0 build_20141024]
at com.ibm.jsse2.pc.a(pc.java:41) ~[na:6.0 build_20141024]
at com.ibm.jsse2.pc.checkServerTrusted(pc.java:1) ~[na:6.0 build_20141024]
at com.ibm.jsse2.pc.b(pc.java:90) ~[na:6.0 build_20141024]
at com.ibm.jsse2.lb.a(lb.java:499) ~[na:6.0 build_20141024]
... 80 common frames omitted
Caused by: java.security.cert.CertPathBuilderException:
PKIXCertPathBuilderImpl could not build a valid CertPath.
at com.ibm.security.cert.PKIXCertPathBuilderImpl.engineBuild(PKIXCertPathBuilderImpl.java:411)
~[na:na]
at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:258)
~[na:na]
at com.ibm.jsse2.util.h.b(h.java:61) ~[na:6.0 build_20141024]
... 86
common frames omitted
Why are certificates being applied for HttpsURLConnection
but not for HttpClient
? What am I doing wrong?
Upvotes: 2
Views: 2612
Reputation: 27528
HttpClient does not take system properties into account unless explicitly configured to do do.
Try replacing
HttpClients.createDefault()
with
HttpClients.createSystem()
Please also note that PoolingHttpClientConnectionManager
instance in your code is not used. Do not create custom connection managers unless you have a very good reason to do so.
Upvotes: 3
Reputation: 3083
The following question has a good code example on how to use HTTPS over HttpClient.
Using Apache httpclient for https
In brief: your code is missing all of the HTTPS specific setup.. you are using it as if it was just a regular HTTP request.
Upvotes: 0