阿卡.如何在https请求中设置pem证书



我使用Akka(2.5.18版(通过https向特定服务器发送JSON字符串。我使用了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"中。这样,相同的actor类可以用于所有客户。

根据文档,我需要创建一个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))

但我不知道如何"设置"这个证书和请求中的私钥(由密码短语保护(,以便服务器接受它

如有任何提示或帮助,我们将不胜感激。

下面允许进行https请求,并使用x.509证书中的私钥来标识自己。

以下库用于管理ssl配置和进行https调用:

  • ssl配置
  • akkahttp

将您的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
}
]
}
}

使用特殊的akka特性DefaultSSLContextCreation加载ssl配置

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配置库来管理证书,而不是自己编程。通过在ssl-config中定义keyManager,在自定义httpsConnectionContext的帮助下完成的任何http请求都将使用证书来识别调用者/客户端。

我重点介绍了如何使用客户端证书建立https连接。省略了用于管理多个证书的任何动态行为。但我希望这段代码能够让你理解如何继续。

最新更新