2014-03-24 236 views
3

現在我正在尋找有關任務如何通過HttpComponentsMessageSender(不相關)爲客戶端x509證書身份驗證重寫不推薦使用的解決方案的解決方案。Apache HttpClient 4.3和x509客戶端證書進行身份驗證

例如,過時的解決方案是:

SSLSocketFactory lSchemeSocketFactory = new SSLSocketFactory(this.keyStore, this.keyStorePassword); 
    Scheme sch = new Scheme("https", 443, lSchemeSocketFactory); 

    DefaultHttpClient httpClient = (DefaultHttpClient)getHttpClient(); 
    httpClient.getConnectionManager().getSchemeRegistry().register(sch); 

與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); 

我還是從服務器獲取禁止403。但是,當我使用解決方案的「已棄用」版本時,它效果很好。 SSL證書已簽署Thawte。

有什麼想法? 感謝

回答

3

托馬斯,也許爲時已晚,但我希望這將有助於其他人...... 有方法,我正在使用使用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; 
    } 
} 

阿帕奇Foundation移動了org.apache.http.conn.ssl.SSLContextBuilder,org.apache.http.conn.ssl.SSLContexts和org.apache.http.conn.ssl.SSLSocketFactory,以4.4版開始,There可以找到Apache Client 4.5.2 API Depracated List。所以,透水方法可以改變這樣的:

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

的NO_OP的HostnameVerifier實質上是將主機名驗證 關閉。這個實現是無操作的,並且永遠不會拋出SSLException。

如果您需要驗證主機名,您可以使用DefaultHostnameVerifier,或者您可以實現自定義主機名驗證程序。

+2

'不推薦使用SSLContexts類型'和'構造函數SSLConnectionSocketFactory(SSLContext,X509HostnameVerifier)'棄用' – KCD

+1

'useTLS()'是無用的,因爲TLS已經是默認協議。 – herau

+0

@KCD謝謝你,我根據你的意見做了修改。 – Daniyar

0

下面是HttpClient的代碼4.4+ (爲4.4+更新@Daniyar代碼)

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; 
    } 
} 
0

您需要創建containts可信CA即trust.jks一個密鑰。在這個密鑰庫中,您應該只放置應用程序要連接的服務器的證書。

然後,您需要服務器標識的密鑰庫,即identity.jks。在這個密鑰庫中,您應該存儲將私鑰+證書+ CA鏈置於您的應用將用於向服務器驗證身份的別名(名稱)下。

然後,你可以建立HttpClient這樣的:

public static HttpClient getHttpClient() throws KeyStoreException, CertificateException, NoSuchAlgorithmException, IOException, UnrecoverableKeyException, KeyManagementException { 

    KeyStore identityKeyStore = KeyStore.getInstance("jks"); 
    identityKeyStore.load(DnieUtils.class.getClassLoader().getResourceAsStream("identity.jks"), "identity_password".toCharArray()); 

    KeyStore trustKeyStore = KeyStore.getInstance("jks"); 
    trustKeyStore.load(DnieUtils.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(); 
} 

要構建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 

對於trust.jks文件您只需要服務器的證書(請參閱https://stackoverflow.com/a/36427118/2692914https://stackoverflow.com/a/7886248/2692914),更改別名沒有問題:

# .crt, .cer into a .jks 
keytool -import -alias trust_alias -file server_certificate.crt \ 
    -keystore trust.jks 
相關問題