We're using http-client 4.3 and have some situation where the EDI trading
partner HTTP server presents an SSL certificate with a CN doesn't match the
service URL's hostname. To support this we're trying to use the following code
to override the default http-client "BrowserCompatHostnameVerifier" strategy on
a case-by-case basis:
private static final PoolingHttpClientConnectionManager connManager =
new PoolingHttpClientConnectionManager()
;
connManager.setDefaultMaxPerRoute(10);
connManager.setMaxTotal(5000);
final RequestConfig requestConfig = RequestConfig.custom()
.setAuthenticationEnabled(bsc.getBasicAuthCfg().isEnabled())
.setConnectTimeout(bsc.getConnTimeoutMs())
.setExpectContinueEnabled(bsc.isExpectContinue())
.setSocketTimeout(bsc.getSoTimeoutMs())
.setStaleConnectionCheckEnabled(bsc.isStaleConnCheck())
.build()
;
final HttpHost httpHost = new HttpHost(
bsc.getUrl().getHost(), bsc.getUrl().getPort()
);
final HttpRoute httpRoute = new HttpRoute(httpHost);
AbstractHttpDeliverTDB.connManager.setMaxPerRoute(
httpRoute, bsc.getMaxConns()
);
final HttpClientBuilder builder = HttpClients.custom()
.setConnectionManager(AbstractHttpDeliverTDB.connManager)
.setDefaultConnectionConfig(
ConnectionConfig.custom().setCharset(charset).build()
)
.setDefaultRequestConfig(requestConfig)
;
// disable hostname verification ... if option is disabled
if(!bsc.isVerifySSLHostname()) {
StringBuilder msg = new StringBuilder(100)
.append("hostname verification disabled in http config:")
.append(" env-id=").append(envId.name())
.append("; tp=").append(partnerId)
.append("; tx=").append(folderNm)
.append("; cfg-nm=").append(cfgDocNm)
;
log.warn(msg);
final SSLContext sslContext = SSLContexts.createSystemDefault();
final SSLConnectionSocketFactory sslSF = new SSLConnectionSocketFactory(
sslContext
, SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER
);
builder.setSSLSocketFactory(sslSF);
}
CloseableHttpClient httpClient = builder.build();
final HttpClientContext httpContext = HttpClientContext.create();
// add login form parameters
UrlEncodedFormEntity urlEntity = new UrlEncodedFormEntity(
formDataList
, context.bscBase.getCharset()
);
// execute login service to get session token
HttpPost request = new HttpPost(urlLogin);
request.setEntity(urlEntity);
HttpResponse response = httpClient.execute(request, httpContext);
The code above results in http-client using the browser compatible strategy
rather than simply ignoring the hostname verification as desired.
10-07 17:00:06.856|FATAL|us bams - 12|
|SBaseDeliverTDB.login(BAMSBaseDeliverTDB.java:351)|bams login failed:
https://nonp-glbl-bam/m3oui/rest/login; err=javax.net.ssl.SSLException:
hostname in certificate didn't match: <nonp-glbl-bam> !=
<nonp-glbl-bam.starbucks.net>
javax.net.ssl.SSLException: hostname in certificate didn't match:
<nonp-glbl-bam> != <nonp-glbl-bam.starbucks.net>
at
org.apache.http.conn.ssl.AbstractVerifier.verify(AbstractVerifier.java:232)
~[apache-httpclient-4.3.jar:4.3]
at
org.apache.http.conn.ssl.BrowserCompatHostnameVerifier.verify(BrowserCompatHostnameVerifier.java:54)
~[apache-httpclient-4.3.jar:4.3]
at
org.apache.http.conn.ssl.AbstractVerifier.verify(AbstractVerifier.java:152)
~[apache-httpclient-4.3.jar:4.3]
at
org.apache.http.conn.ssl.AbstractVerifier.verify(AbstractVerifier.java:133)
~[apache-httpclient-4.3.jar:4.3]
at
org.apache.http.conn.ssl.SSLConnectionSocketFactory.verifyHostname(SSLConnectionSocketFactory.java:289)
~[apache-httpclient-4.3.jar:4.3]
at
org.apache.http.conn.ssl.SSLConnectionSocketFactory.connectSocket(SSLConnectionSocketFactory.java:263)
~[apache-httpclient-4.3.jar:4.3]
at
org.apache.http.impl.conn.HttpClientConnectionOperator.connect(HttpClientConnectionOperator.java:118)
~[apache-httpclient-4.3.jar:4.3]
at
org.apache.http.impl.conn.PoolingHttpClientConnectionManager.connect(PoolingHttpClientConnectionManager.java:314)
~[apache-httpclient-4.3.jar:4.3]
at
org.apache.http.impl.execchain.MainClientExec.establishRoute(MainClientExec.java:357)
~[apache-httpclient-4.3.jar:4.3]
at
org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:218)
~[apache-httpclient-4.3.jar:4.3]
at
org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:194)
~[apache-httpclient-4.3.jar:4.3]
at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:85)
~[apache-httpclient-4.3.jar:4.3]
at
org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:108)
~[apache-httpclient-4.3.jar:4.3]
at
org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:186)
~[apache-httpclient-4.3.jar:4.3]
at
org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:82)
~[apache-httpclient-4.3.jar:4.3]
I'm assuming we've missed something basic in the process of trying to override
hostname verification on a client-by-client basis. Can anyone point out where
we've messed up?
...Pete