2015-06-09 2 views
3

Мой сервер использует TLSv1.2 и требует сертификата клиента для соединений. Я могу посылать запросы на сервер с помощью CURL (Этот запрос работает отлично):Использование клиентских сертификатов с twitter finagle

curl --data "SAMPLETEXT" https://myserver.com/webservice --insecure --key privkey.pem --cert certificate.cert 

(да, сервер имеет самозаверяющий сертификат и требует --insecure флага, нет, я не могу это исправить). Теперь я хочу создать клиент для отправки запросов от кода Scala. MyClient - объект, содержащий необходимые пароли и пути. Для этого я создаю SSLContext:

private val keyStore = { 
    //Setting up BouncyCastle provider for message signing 
    Security.addProvider(new BouncyCastleProvider()) 
    //Loading keystore from specified file 
    val clientStore = KeyStore.getInstance("JKS") 
    val inputStream = new FileInputStream(MyClient.keystore) 
    clientStore.load(inputStream, MyClient.keystorePassword.toCharArray) 
    inputStream.close() 
    clientStore 
    } 

    //Retrieving certificate and key 
    private val cert = keyStore.getCertificate(MyClient.keyAlias).asInstanceOf[X509Certificate] 
    private val key = keyStore.getKey(MyClient.keyAlias, MyClient.keystorePassword.toCharArray).asInstanceOf[PrivateKey] 

    //Creating SSL context 
    private val sslContext = { 
    val context = SSLContext.getInstance("TLS") 
    val tmf: TrustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm) 
    val kmf: KeyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm) 
    kmf.init(keyStore, MyClient.keystorePassword.toCharArray) 
    tmf.init(keyStore) 
    context.init(kmf.getKeyManagers, tmf.getTrustManagers, null) 
    context 
    } 

, а затем использовать его для создания клиента:

private val httpClient = 
    richHttpBuilder(HttpEndpoint(baseUri)) 
    .hostConnectionLimit(1) 
    .tlsWithoutValidation() 
    .tls(sslContext, Some(MyClient.host)) 
    .build() 

, но я все еще получаю ошибку:

The future returned an exception of type: com.twitter.finagle.ChannelWriteException, with message: com.twitter.finagle.SslHandshakeException: General SSLEngine problem at remote address:

Что я делаю не так?

ответ

2

Мне потребовалась неделя, чтобы понять, что я делаю неправильно.

Опции .tlsWithoutValidation() и .tls(sslContext, Some(MyClient.host)) не могут быть использованы в то же время, поскольку они настраивают одно и то же свойство (Transport.TLSClientEngine) строителя.

Существует три решения.

  1. Использовать надлежащий сертификат сервера. К сожалению, это неприменимо.

  2. Добавить сертификат сервера в хранилище ключей. Он будет отмечен как доверенный, и клиент будет счастливо работать без tlsWithoutValidation.

  3. Использование невежественный доверие менеджер, который не проверяет ничего:

    private[this] class IgnorantTrustManager extends X509TrustManager { 
        def getAcceptedIssuers(): Array[X509Certificate] = new Array[X509Certificate](0) 
        def checkClientTrusted(certs: Array[X509Certificate], authType: String) { 
        } 
        def checkServerTrusted(certs: Array[X509Certificate], authType: String) { 
        } 
        } 
    

    Затем используйте его в качестве доверительного управляющего:

    context.init(kmf.getKeyManagers, new IgnorantTrustManager(), null) 
    

    tlsWithoutValidation опция должна быть удалена:

    richHttpBuilder(HttpEndpoint(baseUri)) 
        .hostConnectionLimit(1) 
        .tls(sslContext, Some(YandexClient.host)) 
        .build() 
    

    Это решение устраняет целую цель сертификатов, так что shoul d используется только для испытаний.

Смежные вопросы