When you need to support self-signed SSL certificates in your Apache HttpClient based application you can use the contributed EasySSLProtocolSocketFactory as described in the HttpClient docs.
Instead of using HttpClient’s HostConfiguration object directly you’d modify its protocol socket factory in your code like so:
...
if (config.isAllowSelfSignedCertificates()) {
ProtocolSocketFactory factory = new EasySSLProtocolSocketFactory();
try {
URI uri = new URI(config.getBaseUrl());
int port = uri.getPort();
if (port == -1) {
port = 443;
}
Protocol easyHttps = new Protocol(uri.getScheme(), factory, port);
hostConfiguration.setHost(uri.getHost(), port, easyHttps);
} catch (URISyntaxException e) {
throw new IOException("could not parse URI " + config.getBaseUrl(), e);
}
}
...
Somewhere you’d instantiate a HttpClient object. Then you get its host config through HttpClient#getHostConfiguration() – I stored this in the hostConfiguration variable. The if, the config variable, checking for port, etc. is all my own code and has nothing to do with HttpClient directly.
There is one caveat, though! Never use absolute URIs against the HttpClient 3.x with the EasySSLProtocolSocketFactory in place! If you did you’d get the dreaded
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
I found that the HttpClient 3.x has the following code in its executeMethod() method:
...
if (hostconfig == defaulthostconfig || uri.isAbsoluteURI()) {
// make a deep copy of the host defaults
hostconfig = (HostConfiguration) hostconfig.clone();
if (uri.isAbsoluteURI()) {
hostconfig.setHost(uri);
}
}
...
So, in my case (absolute URI) the modified host config (uses EasySSLProtocolSocketFactory) is cloned.
Problem: since the so called “deep copy” isn’t a proper deep copy the copy’s protocol’s socket factory is no longer EasySSLProtocolSocketFactory but the standard SSLProtocolSocketFactory instead!
Update
Apparently, this behavior is “well known and documented”. Since I couldn’t find anything in the HttpClient 3.x documentation I tried Google again and made note of the following JIRA issues and one particular mailing list entry:
- http://issues.apache.org/jira/browse/HTTPCLIENT-634
- http://issues.apache.org/jira/browse/HTTPCLIENT-683
- http://issues.apache.org/jira/browse/HTTPCLIENT-783
- http://www.mail-archive.com/httpclient-user@jakarta.apache.org/msg03530.html
Please note that HttpClient 4.x does not have this limitation!