2013-08-30 172 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 –