[英]Apache HttpClient 4.3 and x509 client certificate to authenticate
now I looking for solution regarding task how to rewrite deprecated solution for client side x509 certificate authentication via HttpComponentsMessageSender (not relevant). 现在我正在寻找有关如何通过HttpComponentsMessageSender(不相关)重写客户端x509证书身份验证的弃用解决方案的任务的解决方案。
For example, deprecated solution is: 例如,弃用的解决方案是:
SSLSocketFactory lSchemeSocketFactory = new SSLSocketFactory(this.keyStore, this.keyStorePassword);
Scheme sch = new Scheme("https", 443, lSchemeSocketFactory);
DefaultHttpClient httpClient = (DefaultHttpClient)getHttpClient();
httpClient.getConnectionManager().getSchemeRegistry().register(sch);
As new solution with CloseableHttpClient I am using: 作为我使用的CloseableHttpClient的新解决方案:
SSLContextBuilder sslContextBuilder = SSLContexts.custom()
// this key store must contain the key/cert of the client
.loadKeyMaterial(keyStore, keyStorePassword.toCharArray());
if (trustStore != null) {
// this key store must contain the certs needed and trusted to verify the servers cert
sslContextBuilder.loadTrustMaterial(trustStore);
}
SSLContext sslContext = sslContextBuilder.build();
LayeredConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext);
// Create a registry of custom connection socket factories for supported
// protocol schemes / https
Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create()
.register("https", sslsf)
.register("http", new PlainConnectionSocketFactory())
.build();
PoolingHttpClientConnectionManager connPoolControl =
new PoolingHttpClientConnectionManager(socketFactoryRegistry);
setConnPoolControl(connPoolControl);
getClientBuilder().setSSLSocketFactory(sslsf);
I still get 403 forbidden from server. 我仍然从服务器上禁止403。 But when I use "deprecated" version of the solution, it works great. 但是当我使用“弃用”版本的解决方案时,它的效果很好。 SSL certificate is signed Thawte. SSL证书已签署Thawte。
Any idea? 任何的想法? Thanks 谢谢
Tomas, maybe it's too late, but I hope it will help others... There is the method, which I'm using to create CloseableHttpClient using Apache HttpClient 4.3: Tomas,也许为时已晚,但我希望它会帮助其他人......有一种方法,我用它来创建使用Apache HttpClient 4.3的CloseableHttpClient:
public static CloseableHttpClient prepareClient() {
try {
SSLContext sslContext = SSLContexts.custom().loadTrustMaterial(null, new TrustSelfSignedStrategy()).useTLS().build();
HttpClientBuilder builder = HttpClientBuilder.create();
SSLConnectionSocketFactory sslConnectionFactory = new SSLConnectionSocketFactory(sslContext, SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
builder.setSSLSocketFactory(sslConnectionFactory);
Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create()
.register("https", sslConnectionFactory)
.register("http", new PlainConnectionSocketFactory())
.build();
HttpClientConnectionManager ccm = new BasicHttpClientConnectionManager(registry);
builder.setConnectionManager(ccm);
return builder.build();
} catch (Exception ex) {
return null;
}
}
Apache Foundation moved org.apache.http.conn.ssl.SSLContextBuilder, org.apache.http.conn.ssl.SSLContexts and org.apache.http.conn.ssl.SSLSocketFactory to deprecated starting with 4.4 version, There you can find Apache Client 4.5.2 API Depracated List. Apache基金会将org.apache.http.conn.ssl.SSLContextBuilder,org.apache.http.conn.ssl.SSLContexts和org.apache.http.conn.ssl.SSLSocketFactory从4.4版本开始弃用, 在那里你可以找到Apache客户端4.5.2 API已删除列表。 So, pervious method can be changed like this: 因此,可以像这样改变以前的方法:
public static CloseableHttpClient prepareClient() {
try {
SSLContext sslContext = SSLContexts.custom()
.loadTrustMaterial(null, new TrustSelfSignedStrategy()).build();
HttpClientBuilder builder = HttpClientBuilder.create();
SSLConnectionSocketFactory sslConnectionFactory =
new SSLConnectionSocketFactory(sslContext.getSocketFactory(),
new NoopHostnameVerifier());
builder.setSSLSocketFactory(sslConnectionFactory);
Registry<ConnectionSocketFactory> registry =
RegistryBuilder.<ConnectionSocketFactory>create()
.register("https", sslConnectionFactory)
.register("http", new PlainConnectionSocketFactory())
.build();
HttpClientConnectionManager ccm = new BasicHttpClientConnectionManager(registry);
builder.setConnectionManager(ccm);
return builder.build();
} catch (Exception ex) {
LOG.error("couldn't create httpClient!! {}", ex.getMessage(), ex);
return null;
}
}
NoopHostnameVerifier NoopHostnameVerifier
The NO_OP HostnameVerifier essentially turns hostname verification off. NO_OP HostnameVerifier实质上关闭了主机名验证。 This implementation is a no-op, and never throws the SSLException. 这个实现是一个无操作,并且永远不会抛出SSLException。
If you need to verify hostname, you can use DefaultHostnameVerifier or you can implement your custom hostname verifier. 如果需要验证主机名,可以使用DefaultHostnameVerifier,也可以实现自定义主机名验证程序。
You need to create a keystore that containts the trusted CAs ie trust.jks
. 您需要创建一个包含可信CA的密钥库,即trust.jks
。 In this keystore you should put only the certificate of the server that your application is going to connect. 在此密钥库中,您应该只放置应用程序要连接的服务器的证书。
Then, you need a keystore for the identity of the server ie identity.jks
. 然后,您需要一个用于服务器identity.jks
的密钥库,即identity.jks
。 In this keystore you should store put the private key + certificate + CA chain under an alias (a name) that your application is going to use to authenticate itself with the server. 在此密钥库中,您应该将私钥+证书+ CA链存放在应用程序将用于向服务器验证自身的别名(名称)下。
Then you could build the HttpClient
like this: 然后你可以像这样构建HttpClient
:
public static HttpClient getHttpClient() throws KeyStoreException, CertificateException, NoSuchAlgorithmException, IOException, UnrecoverableKeyException, KeyManagementException {
KeyStore identityKeyStore = KeyStore.getInstance("jks");
identityKeyStore.load(MyClass.class.getClassLoader().getResourceAsStream("identity.jks"), "identity_password".toCharArray());
KeyStore trustKeyStore = KeyStore.getInstance("jks");
trustKeyStore.load(MyClass.class.getClassLoader().getResourceAsStream("trust.jks"), "trust_password".toCharArray());
SSLContext sslContext = SSLContexts
.custom()
// load identity keystore
.loadKeyMaterial(identityKeyStore, "identity_password".toCharArray(), new PrivateKeyStrategy() {
@Override
public String chooseAlias(Map<String, PrivateKeyDetails> aliases, Socket socket) {
return "identity_alias";
}
})
// load trust keystore
.loadTrustMaterial(trustKeyStore, null)
.build();
SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(sslContext,
new String[]{"TLSv1.2", "TLSv1.1"},
null,
SSLConnectionSocketFactory.getDefaultHostnameVerifier());
return HttpClients.custom()
.setSSLSocketFactory(sslConnectionSocketFactory)
.build();
}
To build the identity.jks
, you need the CAs chain, the public key and the private key: 要构建identity.jks
,您需要CA链,公钥和私钥:
$1 = mycustomidentity
# make the keycert bundle for pkcs12 keystore
cat intermediate/certs/ca-chain.cert.pem \
intermediate/certs/$1.cert.pem \
intermediate/private/$1.key.pem \
> intermediate/keycerts/$1.full-chain.keycert.pem
# generate the pkcs12 keystore with the alias of the server url
openssl pkcs12 -export \
-in intermediate/keycerts/$1.full-chain.keycert.pem \
-out intermediate/pkcs12s/$1.full-chain.p12 \
-name $1 \
-noiter -nomaciter
# .p12 to .jks
keytool -importkeystore -srckeystore $1.full-chain.p12 \
-srcstoretype pkcs12 -srcalias $1 \
-destkeystore identity.jks -deststoretype jks \
-deststorepass identity_password -destalias identity_alias
For the trust.jks
file you only need the certificate of the server (see https://stackoverflow.com/a/36427118/2692914 or https://stackoverflow.com/a/7886248/2692914 ), there is no problem in changing the alias: 对于trust.jks
文件,您只需要服务器的证书(参见https://stackoverflow.com/a/36427118/2692914或https://stackoverflow.com/a/7886248/2692914 ),没有问题更改别名:
# .crt, .cer into a .jks
keytool -import -alias trust_alias -file server_certificate.crt \
-keystore trust.jks
Below is the code for HttpClient 4.4+ (updated @Daniyar code for 4.4+) 下面是HttpClient 4.4+的代码(更新的@Daniyar代码为4.4+)
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.DefaultHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.TrustSelfSignedStrategy;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.ssl.SSLContexts;
public static CloseableHttpClient createApacheHttp4ClientWithClientCertAuth() {
try {
SSLContext sslContext = SSLContexts
.custom()
.loadTrustMaterial(null, new TrustSelfSignedStrategy())
.build();
SSLConnectionSocketFactory sslConnectionFactory = new SSLConnectionSocketFactory(sslContext,
new DefaultHostnameVerifier());
Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory> create()
.register("https", sslConnectionFactory)
.register("http", new PlainConnectionSocketFactory())
.build();
HttpClientBuilder builder = HttpClientBuilder.create();
builder.setSSLSocketFactory(sslConnectionFactory);
builder.setConnectionManager(new PoolingHttpClientConnectionManager(registry));
return builder.build();
} catch (Exception ex) {
return null;
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.