2013-08-30 177 views
4

我想在服务A和B之间使用相互SSL认证。我目前正在实现从Java服务A中传递客户端证书。我正在使用Apache DefaultHttpClient执行我的请求。我能够从内部凭证管理器检索我的服务A的客户端证书,并将其保留为字节数组。如何使用HTTP客户端传递客户端证书?

DefaultHttpClient client = new DefaultHttpClient(); 
byte [] certificate = localCertManager.retrieveCert(); 

我在这方面的经验很少,我很感谢您的帮助!

我想也许它应该以某种方式通过HTTP客户端或可能在标题中的参数。

如何将客户端证书传递给HTTP客户端?

回答

8

您需要告诉SSLSocketFactory(org.apache.http,而不是javax)您的密钥库,并配置DefaultHTTPClient以将其用于https连接。

一个例子是在这里:http://hc.apache.org/httpcomponents-client-ga/httpclient/examples/org/apache/http/examples/client/ClientCustomSSL.java

+0

很酷,这真的很有帮助! – agerrr

+0

这开始是模糊的,但链接的示例通过不使用客户端证书来混淆事物。它实际上设置了替代的CA证书来替代正在连接的服务器,但是对于不熟悉** SSLContexts **的人来说,这可能是一个正确的例子。我遵循这一点,并花了很多时间来解决** loadTrustMaterial **不起作用。 –

2

客户端证书是sent during the TLS handshake建立连接,并且不能经由HTTP该连接内发送时。

通信层叠这样的:内

  • TLS(表示层协议)内
  • TCP(传送层协议)内
    • HTTP(应用层协议) IP(网络层协议)

    您需要在TLS握手期间发送客户端证书可以影响HTTP(方法,头文件,URL,请求主体)。服务器不会接受稍后发送的客户端证书。

    我推荐从DefaultHttpClient开关(不建议使用)到CloseableHttpClient与尝试,与资源更清洁工作。

    Apache HttpClient 4.5使Mutual TLS合理地方便。这个答案已经通过Apache HttpClient 4.5.3测试。

    的基本出发点是利用loadKeyMaterial加载客户证书模板,它的键(客户端密钥对)到的SSLContext

    SSLContext sslContext = SSLContexts.custom().loadKeyMaterial(
           MutualHttpsMain.class.getResource(TEST_CLIENT_KEYSTORE_RESOURCE), 
           password, password, 
           (aliases, socket) -> aliases.keySet().iterator().next() 
         ).build(); 
    

    最后建立与套接字工厂HTTP客户端:

    CloseableHttpClient httpclient = HttpClients 
         .custom().setSSLContext(sslContext).build(); 
    

    与该客户端,所有请求可以相互TLS认证执行表现:

    CloseableHttpResponse closeableHttpResponse = httpclient.execute(
         new HttpGet(URI.create("https://mutual-tls.example.com/"))); 
    

    这里的相互TLS的与Apache HttpClient的一个完整的可运行的例子:

    import org.apache.http.HttpEntity; 
    import org.apache.http.StatusLine; 
    import org.apache.http.client.methods.CloseableHttpResponse; 
    import org.apache.http.client.methods.HttpGet; 
    import org.apache.http.impl.client.CloseableHttpClient; 
    import org.apache.http.impl.client.HttpClients; 
    import org.apache.http.ssl.SSLContexts; 
    
    import javax.net.ssl.SSLContext; 
    import java.io.Console; 
    import java.io.IOException; 
    import java.io.InputStream; 
    import java.net.URI; 
    import java.nio.ByteBuffer; 
    import java.nio.channels.Channels; 
    import java.nio.channels.ReadableByteChannel; 
    import java.nio.channels.WritableByteChannel; 
    import java.security.GeneralSecurityException; 
    
    public class MutualHttpsMain { 
        private static final String TEST_URL = "https://mutual-tls.example.com/"; 
        private static final String TEST_CLIENT_KEYSTORE_RESOURCE = "/mutual-tls-keystore.p12"; 
    
        public static void main(String[] args) throws GeneralSecurityException, IOException { 
         Console console = System.console(); 
         char[] password = console.readPassword("Keystore password: "); 
         SSLContext sslContext = SSLContexts.custom().loadKeyMaterial(
           MutualHttpsMain.class.getResource(TEST_CLIENT_KEYSTORE_RESOURCE), 
           password, password, 
           (aliases, socket) -> aliases.keySet().iterator().next() 
         ).build(); 
         try (CloseableHttpClient httpclient = HttpClients 
           .custom().setSSLContext(sslContext).build(); 
          CloseableHttpResponse closeableHttpResponse = httpclient.execute(
            new HttpGet(URI.create(TEST_URL)))) { 
          console.writer().println(closeableHttpResponse.getStatusLine()); 
          HttpEntity entity = closeableHttpResponse.getEntity(); 
          try (InputStream content = entity.getContent(); 
           ReadableByteChannel src = Channels.newChannel(content); 
           WritableByteChannel dest = Channels.newChannel(System.out)) { 
           ByteBuffer buffer = ByteBuffer.allocateDirect(16 * 1024); 
           while (src.read(buffer) != -1) { 
            buffer.flip(); 
            dest.write(buffer); 
            buffer.compact(); 
           } 
           buffer.flip(); 
           while (buffer.hasRemaining()) 
            dest.write(buffer); 
          } 
         } 
        } 
    } 
    

    它通常最好使用摇篮或Maven运行这样的事情,但在保持这个牦牛剃须的利益尽可能最小化我提供基线JDK指令来构建和运行此指令。从以下页面

    下载JAR文件:

    保存上面的完整的例子为MutualHttpsMain.java

    将您的PKCS#12复制到mutual-tls-keystore.p12在同一目录中。

    编译如下(在Mac OS/Linux的/ * nix中-喜欢):

    javac MutualHttpsMain.java -cp httpclient-4.5.3.jar:httpcore-4.4.8.jar 
    

    或Windows:

    javac MutualHttpsMain.java -cp httpclient-4.5.3.jar;httpcore-4.4.8.jar 
    

    运行如下(在Mac OS/Linux的/ * nix-喜欢):

    java -cp httpclient-4.5.3.jar:commons-codec-1.10.jar:commons-logging-1.2.jar:httpcore-4.4.8.jar:. MutualHttpsMain 
    

    运行如下(在Windows上):

    java -cp httpclient-4.5.3.jar;commons-codec-1.10.jar;commons-logging-1.2.jar;httpcore-4.4.8.jar;. MutualHttpsMain 
    
  • +0

    @magnus有一个简洁的示例相互TLS java HTTP客户端示例https://stackoverflow.com/a/32513368/154527 –