2014-03-24 320 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 
相关问题