HttpClient如何访问需要提交客户端证书的SSL服务

1.1 问题背景

自从***一期工程上了CA认证网关之后,在访问受CA认证网关保护的应用子系统时,必须提交客户端证书。那么问题来了,如果是人工(通过IE浏览器)访问子系统自然没问题,访问时会提示选择证书,输入PIN码等等,照做即可。但是如果是应用程序去访问呢?例如,A子系统提供了外部接口程序,由于受到CA认证网关的“保护”,外部程序如何访问A子系统的接口呢?

1.2 问题分析

应用程序自然没法像人工一样,借助浏览器访问应用子系统。此时外部应用程序如果直接通过HttpGet或HttpPost去访问应用子系统的接口时,会抛异常。

由于上了CA认证网关之后,实现的是应用系统访问的双向身份认证,即:客户端须验证服务端的身份,服务端也须验证客户端的身份。为了实现双向身份认证,客户端须安装服务端提供的服务端证书,并且客户端在访问服务端时须提交客户端证书。只有这样才能实现应用系统的正常访问。对于人工访问是如此,对于应用程序访问亦是如此。

令人庆幸的是,ApacheHttpClient提供了基于双向认证机制访问SSL服务的支持。HttpClient通过自定义一个携带证书的SSL连接,实现对需双向认证的服务的访问。

1.3 解决方案

1.3.1 准备工作

结合当前案例的实际情况,有一些准备工作要做:

1、    制作客户端带私钥的软证书,并转化成JKS格式。操作步骤如下:

1)、在用户管理中心注册用户,并推送到证书注册中心;

2)、登录证书注册中心,首先更新用户信息,把证书类型修改为“RSA个人单向证书”(默认是“RSA个人双向证书”);


3)、制作证书,在“签发个人证书”时,“证书设备”选择第二个选项(即:MicrosoftEnhanced Cryptographic Provider v1.0)


4)、导出证书:证书制作完成后就可以在IE的Internet选项-内容-证书列表中看到,然后选中该证书,点击导出。导出过程中注意选择“是,导出私钥(Y)”,如图所示:


然后下一步,输入私钥(123456):


最后导出一个.pfx格式的个人证书:


5)、把pfx格式证书转换为JKS格式(pfx格式的证书无法直接引用,需要转换成keystore格式,JKS就是keystore格式之一)。至于如何转换,百度一下,你就知道。

2、    把服务端证书(证书链)导入trust.keystore中备用。

在本案例中,服务端证书(证书链)包括ROOT.cer和CA.cer。这两个证书须导入trust.keystore。用JDK自带的keytool工具实现导入:

keytool-import -alias Root -file d:/Root.cer -keystore "d:/trust.keystore" -storepass123456

keytool-import -alias CA -file d:/CA.cer -keystore "d:/trust.keystore"-storepass 123456

3、    在网关上添加用户,并授予角色。

针对刚刚制作的证书,所关联的用户需在网关上手动录入,并添加到相应的角色中。只有这样,才能通过CA认证网关的系统级权限验证。操作步骤不再赘述。

1.3.2 访问应用子系统

ApacheHttpClient实现携带证书访问SSL服务的基本原理是:首先加载私钥证书到一个KeyStore中,并把服务端可信任证书加载到一个Trusted KeyStore中;然后用这两个KeyStore构造一个SSLContext对象,最终实例化一个CloseableHttpClient对象,并通过CloseableHttpClient去访问SSL服务。

源码:

import java.io.File;

import java.io.FileInputStream;

import java.security.KeyStore;

 

importjavax.net.ssl.SSLContext;

 

import org.apache.http.HttpEntity;

import org.apache.http.client.methods.CloseableHttpResponse;

import org.apache.http.client.methods.HttpGet;

import org.apache.http.conn.ssl.SSLConnectionSocketFactory;

import org.apache.http.conn.ssl.SSLContexts;

import org.apache.http.conn.ssl.TrustSelfSignedStrategy;

import org.apache.http.impl.client.CloseableHttpClient;

import org.apache.http.impl.client.HttpClients;

import org.apache.http.util.EntityUtils;

/**

*ThisexampledemonstrateshowtocreatesecureconnectionswithacustomSSLcontext.

*/

public  class MyClientCustomSSL {

 private final static StringTEST_URL ="https://125.35.24.152:446/sfda/HelloWorldServlet";

private final static StringKEYSTORE_FILE ="d:/00000190.jks";

private final static StringTRUSTSTORE_FILE ="d:/trust.keystore";

private final static StringKEYSTORE_PASSWORD ="123456";

 

    public final static void main(String[] args) throws Exception {

    //load the CA CERT(private key):

KeyStore keyStore  =KeyStore.getInstance(KeyStore.getDefaultType());

FileInputStream instream =

new FileInputStream(new File(KEYSTORE_FILE));

try {

        keyStore.load(instream,KEYSTORE_PASSWORD.toCharArray());

} finally {

             instream.close();

}

//load the trusted certs:

KeyStore trustStore  = KeyStore.getInstance(KeyStore.getDefaultType());

FileInputStream instream1=

new FileInputStream(new File(TRUSTSTORE_FILE));

try {

     trustStore.load(instream1,KEYSTORE_PASSWORD.toCharArray());

} finally {

     instream1.close();

}

// Trust own CA and allself-signed certs

SSLContext sslcontext= SSLContexts.custom()

.loadKeyMaterial(keyStore,KEYSTORE_PASSWORD.toCharArray())

.loadTrustMaterial(trustStore,new TrustSelfSignedStrategy())

.build();

// Allow TLSv1 protocol only

SSLConnectionSocketFactorysslsf =

new SSLConnectionSocketFactory(sslcontext,

                         new String[] {"TLSv1" },

                                null,

SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);

         CloseableHttpClient httpclient =HttpClients.custom()

                 .setSSLSocketFactory(sslsf)

                 .build();

try {

HttpGet httpget = new HttpGet(TEST_URL);

System.out.println("ExecutingRequest:" + httpget.getRequestLine());

CloseableHttpResponseresponse = httpclient.execute(httpget);

try {

         HttpEntity entity =response.getEntity();

         System.out.println("-------------------------------------");

System.out.println(response.getStatusLine());

System.out.println(EntityUtils.toString(entity));

         EntityUtils.consume(entity);

     } finally {

response.close();

}

} finally {

 httpclient.close();

}

}

}

1.4 附录

1.4.1 HttpClient4.3官方下载

http://hc.apache.org/httpcomponents-client-4.3.x/download.html

1.4.2 官方示例ClientCustomSSL下载

http://hc.apache.org/httpcomponents-client-4.3.x/httpclient/examples/org/apache/http/examples/client/ClientCustomSSL.java

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值