2014-03-24 4 views
3

인증 이제 HttpComponentsMessageSender (관련 없음)를 통해 클라이언트 측 x509 인증서 인증을 위해 사용되지 않는 솔루션을 다시 작성하는 방법에 대한 해결책을 찾고 있습니다.Apache HttpClient 4.3 및 x509 클라이언트 인증서

예를 들어, 사용되지 않는 솔루션입니다 : CloseableHttpClient 새로운 솔루션은 내가 사용하고

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

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

으로 :

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 서버에서 금지 얻을. 그러나 "deprecated"버전의 솔루션을 사용하면 멋지게 작동합니다. SSL 인증서에 서명 됨 Thawte.

아이디어가 있으십니까? 감사

답변

3

토마스, 어쩌면 너무 늦었 어,하지만 난 아파치 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 버전부터 deprecated로 옮겼습니다. There 아파치 클라이언트를 찾을 수 있습니다. 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은 기본적으로 호스트 이름 확인을 오프집니다. 이 구현은 no-op이며, 절대로 SSLException을 던지지 않습니다.

호스트 이름을 확인해야하는 경우 DefaultHostnameVerifier를 사용하거나 사용자 지정 호스트 이름 확인 프로그램을 구현할 수 있습니다.

+2

'SSLContexts 유형은 더 이상 사용되지 않으며'생성자 SSLConnectionSocketFactory (SSLContext, X509HostnameVerifier)는 사용되지 않습니다' – KCD

+1

TLS는 이미 기본 프로토콜이므로'useTLS()'는 쓸모가 없습니다. – herau

+0

@KCD 감사합니다. 귀하의 의견에 따라 변경했습니다. – Daniyar

0

다음은 HttpClient를위한 코드 4.4 (4.4 업데이트 된 @Daniyar 코드) 당신은 신뢰할 수있는 CA 즉 trust.jks을 containts 키 스토어를 만들 필요가

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

입니다. 이 키 저장소에서는 응용 프로그램이 연결할 서버의 인증서 만 넣어야합니다.

그런 다음 서버 ID (예 : 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의 체인, 공개 키와 개인 키가 필요 다음 trust.jks 파일의 경우

$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 

을 서버 인증서 (https://stackoverflow.com/a/36427118/2692914 또는 https://stackoverflow.com/a/7886248/2692914 참조) 만 있으면 별칭을 변경하는 데 문제가 없습니다.

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