Акка.Как установить сертификат pem в запросе https - PullRequest
0 голосов
/ 11 декабря 2018

Я использую Akka (версия 2.5.18) для отправки строк JSON на определенный сервер через https.Я использовал poolRouter (балансировочный пул с 10 экземплярами) для создания пула актеров, которые собираются отправлять JSON (сгенерированные от разных клиентов) на один сервер:

  val router: ActorRef = system.actorOf(
    FromConfig.props(Props(new SenderActor(configuration.getString("https://server.com"), this.self))),
    "poolRouter"
  )

В спецификации проекта сказано, что запросы также могут быть отправлены с помощью curl:

curl -X PUT --cert certificate.pem --key private.key -H 'Content-Type: application / json' -H 'cache-control: no-cache' -d '[{"id" : "test"}] 'https://server.com'

Где "certificate.pem" - это сертификат tls клиента, а "private.key" - используемый закрытый ключ.для создания CSR клиента.

Я использую балансировочный пул, потому что у меня будет очень большой набор сертификатов (по одному для каждого клиента), и мне нужно отправлять запросы одновременно.

Мой подход заключается в том, чтобы иметь класс "SenderActor", который будет создан балансирующим пулом.Каждый участник после получения сообщения с «customerId» и данными JSON, сгенерированными этим клиентом, отправит запрос https:

  override def receive: Receive = {
    case Data(customerId, jsonData) =>
      send(customerId(cid, jsonData))

Каждый SenderActor прочитает сертификат (и закрытый ключ)на основе пути с использованием customerId.Например, customerId: «cust1» будет хранить свой сертификат и ключ в «/ home / test / cust1».Таким образом, один и тот же класс акторов может использоваться для всех клиентов.

В соответствии с документацией , мне нужно создать HttpsConnectionContext для отправки различных запросов:

def send(customerId: String, dataToSend): Future[HttpResponse] = {

    // Create the request
    val req = HttpRequest(
      PUT,
      uri = "https://server.com",
      entity = HttpEntity(`application/x-www-form-urlencoded` withCharset `UTF-8`, dataToSend),
      protocol = `HTTP/1.0`)

    val ctx: SSLContext = SSLContext.getInstance("TLS")

    val permissiveTrustManager: TrustManager = new X509TrustManager() {
      override def checkClientTrusted(chain: Array[X509Certificate], authType: String): Unit = {}
      override def checkServerTrusted(chain: Array[X509Certificate], authType: String): Unit = {}
      override def getAcceptedIssuers(): Array[X509Certificate] = Array.empty
    }


    ctx.init(Array.empty, Array(permissiveTrustManager), new SecureRandom())
    val httpsConnContext: HttpsConnectionContext = ConnectionContext.https(ctx)

    // Send the request
    Http(system).singleRequest(req, httpsConnContext)
}

Проблема, с которой я столкнулся, заключается в том, что я не имею ни малейшего понятия о том, как «установить сертификат и ключ» в запросе, чтобы сервер их принимал.

Например,Я могу прочитать сертификат, используя следующий код:

import java.util.Base64

val certificate: String => String = (customer: String) => IO {
Source.fromInputStream(getClass.getClassLoader
  .getResourceAsStream("/home/test/".concat(customer).concat("_cert.pem")))
  .getLines().mkString
}.unsafeRunSync()

val decodedCertificate = Base64.getDecoder.decode(certificate(customerId)
  .replaceAll(X509Factory.BEGIN_CERT, "").replaceAll(X509Factory.END_CERT, ""))
val cert: Certificate = CertificateFactory.getInstance("X.509")
  .generateCertificate(new ByteArrayInputStream(decodedCertificate))

Но я не знаю, как «установить» этот сертификат и закрытый ключ в запросе (который защищен парольной фразой), поэтомучто сервер это принимает.

Любая подсказка или помощь будет принята с благодарностью.

1 Ответ

0 голосов
/ 13 декабря 2018

Следующее позволяет сделать запрос https и идентифицировать себя с помощью закрытого ключа из сертификата x.509.

Следующие библиотеки используются для управления конфигурацией ssl и совершения вызовов https:

Преобразование сертификата pem в формат pks12 в соответствии с определением здесь

openssl pkcs12 -export -out certificate.pfx -inkey privateKey.key -in certificate.crt

Определите хранилище ключей в вашем application.conf.Он поддерживает только pkcs12, и из-за этого необходим шаг 1.

ssl-config {
  keyManager {
    stores = [
      {
        type = "pkcs12"
        path = "/path/to/pkcs12/cetificate"
        password = changeme //the password is set when using openssl
      }
    ]
  }
}

Загрузка конфигурации ssl с использованием специальной черты akka DefaultSSLContextCreation

import akka.actor.ActorSystem
import akka.actor.ExtendedActorSystem
import akka.http.scaladsl.DefaultSSLContextCreation
import com.typesafe.sslconfig.akka.AkkaSSLConfig
import com.typesafe.sslconfig.ssl.SSLConfigFactory

class TlsProvider(val actorSystem: ActorSystem) extends DefaultSSLContextCreation {

  override protected def sslConfig: AkkaSSLConfig =
    throw new RuntimeException("Unsupported behaviour when creating new sslConfig")

  def httpsConnectionContext() = {
    val akkaSslConfig =
      new AkkaSSLConfig(system.asInstanceOf[ExtendedActorSystem], SSLConfigFactory.parse(system.settings.config))
    createClientHttpsContext(akkaSslConfig)
  }
}

Создание контекста https и использование в http-соединениибассейн.

 Http(actorSystem).cachedHostConnectionPoolHttps[RequestContext](
            host = host,
            port = portValue,
            connectionContext = new TlsProvider(actorSystem).httpsConnectionContext()
          )

Или установите контекст подключения на метод Http(actorSystem).singleRequest.

В заключение, я использовал библиотеку ssl-config для управления сертификатами, а не делал это самостоятельно программно.Определяя keyManager в ssl-config, любой http-запрос, выполняемый с помощью custom httpsConnectionContext, будет использовать сертификат для идентификации вызывающего абонента / клиента.

Я сосредоточился на описании того, как установить соединение httpsиспользуя сертификат клиента.Любое динамическое поведение для управления несколькими сертификатами опущено.Но я надеюсь, что этот код сможет дать вам понимание, как действовать.

...