如何配置Apache HttpClient 4.x以使用特定的Websphere SSL别名?

时间:2013-06-18 15:48:51

标签: authentication ssl websphere apache-httpclient-4.x

使用Websphere尝试使用HttpClient 4.x(当前版本为4.2.1)连接到外部系统时,我们的环境存在问题。连接到外部系统很好,他们的证书安装在Websphere中,没有额外的HttpClient配置。但是,当它们启用相互身份验证时,它将不再起作用,并且我们会收到SSLPeerUnverifiedException异常:

javax.net.ssl.SSLPeerUnverifiedException: peer not authenticated,
at com.ibm.jsse2.SSLSessionImpl.getPeerCertificates(SSLSessionImpl.java:105),
at org.apache.http.conn.ssl.AbstractVerifier.verify(AbstractVerifier.java:128),
at org.apache.http.conn.ssl.SSLSocketFactory.connectSocket(SSLSocketFactory.java:572),
at org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:180),
at org.apache.http.impl.conn.ManagedClientConnectionImpl.open(ManagedClientConnectionImpl.java:294),
at org.apache.http.impl.client.DefaultRequestDirector.tryConnect(DefaultRequestDirector.java:640),
at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:479),
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:906),
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:1066),

我提供了以下代码示例,我想知道是否有任何方法可以配置HttpClient来使用像此代码示例那样的显式别名。我试图找到关于在HttpClient 4上使用SSL相互身份验证的好文档,并且找不到多少。

以下是代码示例:

private HttpURLConnection getConnection(String server, String machine,
String port) throws Exception {
URL u = new URL(server);
HttpsURLConnection connection = (HttpsURLConnection) u.openConnection();
String alias = "CellDefaultSSLSettings";

final HashMap connectionInfo = new HashMap();
connectionInfo.put(JSSEHelper.CONNECTION_INFO_DIRECTION,
JSSEHelper.DIRECTION_OUTBOUND);
connectionInfo.put(JSSEHelper.CONNECTION_INFO_REMOTE_HOST, machine);
connectionInfo.put(JSSEHelper.CONNECTION_INFO_REMOTE_PORT, port);

javax.net.ssl.SSLSocketFactory sslFact = JSSEHelper.getInstance()
.getSSLSocketFactory(alias, connectionInfo, null);

connection.setSSLSocketFactory(sslFact);
connection.setDoOutput(true);
connection.setDoInput(true);
connection.setRequestMethod("POST");
return connection;
}

基本上,如何让HttpClient使用“CellDefaultSSLSettings”?

2 个答案:

答案 0 :(得分:2)

从根本上说,这个问题与HttpClient无关。可以将HttpClient配置为使用任何自定义SSLContextSSLSocketFactory实例建立HTTPS连接。这基本上是关于如何使用JSSE API以正确的方式配置SSLContext。在您的特定情况下,JSSEHelper会为您完成所有艰苦的工作。

// JSSE socket factory
javax.net.ssl.SSLSocketFactory jssesf = JSSEHelper.getInstance().getSSLSocketFactory(alias, connectionInfo, null);
// HC socket factory
SSLSocketFactory hcsf = new SSLSocketFactory(jssesf, SSLSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);

这将给出一个可以通过连接管理器注册的连接套接字工厂。

HttpClient 4.3还附带了SSLContextBuilder类,可用于使用流体构建器API组装自定义SSL配置。

https://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/conn/ssl/SSLContextBuilder.java

答案 1 :(得分:0)

oleg的回答帮助了我。

我所做的是扩展DefaultHttpClient,每个构造函数都为目标URL获取一个String参数,并调用方法setupScheme:

private void setupScheme(final String url) throws Exception {
    Scheme scheme = new Scheme("https", 443, retrieveWebsphereSSLConnectionFactory(url));
    getConnectionManager().getSchemeRegistry().register(scheme);
}

方法retrieveWebsphereSSLConnectionFactory基本上将样本中的代码与提供的代码oleg结合起来:

private SchemeSocketFactory retrieveWebsphereSSLConnectionFactory(final String url)
        throws SSLException, URISyntaxException {
    final String alias = "CellDefaultSSLSettings";

    final HashMap<String, String> connectionInfo = new HashMap<String, String>();
    connectionInfo.put(JSSEHelper.CONNECTION_INFO_DIRECTION, JSSEHelper.DIRECTION_OUTBOUND);
    connectionInfo.put(JSSEHelper.CONNECTION_INFO_REMOTE_HOST,
            URIUtils.extractHost(new URI(url)).getHostName());
    connectionInfo.put(JSSEHelper.CONNECTION_INFO_REMOTE_PORT, "443");

    return new SSLSocketFactory(JSSEHelper.getInstance().getSSLSocketFactory(alias, connectionInfo, null),
            SSLSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
}