如何使用akka-http对自我认证的服务器进行POST调用

时间:2017-11-17 10:55:53

标签: scala ssl akka akka-stream akka-http

我有一个akka-streams拓扑,我使用akka-http进行POST调用。

在将请求发送到不安全的服务器(具有自签名证书)时,我遇到以下错误。它是一个内部服务器,所以从安全的角度来看我很好。

javax.net.ssl.SSLHandshakeException: General SSLEngine problem
    at sun.security.ssl.Handshaker.checkThrown(Handshaker.java:1478) ~[?:1.8.0_131]
    at sun.security.ssl.SSLEngineImpl.checkTaskThrown(SSLEngineImpl.java:535) ~[?:1.8.0_131]
    at sun.security.ssl.SSLEngineImpl.readNetRecord(SSLEngineImpl.java:813) ~[?:1.8.0_131]
    at sun.security.ssl.SSLEngineImpl.unwrap(SSLEngineImpl.java:781) ~[?:1.8.0_131]
    at javax.net.ssl.SSLEngine.unwrap(SSLEngine.java:624) ~[?:1.8.0_131]
    at akka.stream.impl.io.TLSActor.akka$stream$impl$io$TLSActor$$doUnwrap(TLSActor.scala:367) ~[akka-stream_2.11-2.4.17.jar:?]
    at akka.stream.impl.io.TLSActor.akka$stream$impl$io$TLSActor$$doInbound(TLSActor.scala:290) ~[akka-stream_2.11-2.4.17.jar:?]
    at akka.stream.impl.io.TLSActor$$anonfun$1.apply$mcV$sp(TLSActor.scala:225) ~[akka-stream_2.11-2.4.17.jar:?]
    at akka.stream.impl.Pump$class.pump(Transfer.scala:199) ~[akka-stream_2.11-2.4.17.jar:?]
    at akka.stream.impl.io.TLSActor.pump(TLSActor.scala:48) ~[akka-stream_2.11-2.4.17.jar:?]
    at akka.stream.impl.BatchingInputBuffer.enqueueInputElement(ActorProcessor.scala:90) ~[akka-stream_2.11-2.4.17.jar:?]
    at akka.stream.impl.BatchingInputBuffer$$anonfun$upstreamRunning$1.applyOrElse(ActorProcessor.scala:141) ~[akka-stream_2.11-2.4.17.jar:?]
    at scala.runtime.AbstractPartialFunction.apply(AbstractPartialFunction.scala:36) ~[scala-library-2.11.8.jar:?]
    at akka.stream.impl.SubReceive.apply(Transfer.scala:16) ~[akka-stream_2.11-2.4.17.jar:?]
    at akka.stream.impl.FanIn$InputBunch$$anonfun$subreceive$1.applyOrElse(FanIn.scala:234) ~[akka-stream_2.11-2.4.17.jar:?]
    at scala.runtime.AbstractPartialFunction.apply(AbstractPartialFunction.scala:36) ~[scala-library-2.11.8.jar:?]
    at akka.stream.impl.SubReceive.apply(Transfer.scala:16) ~[akka-stream_2.11-2.4.17.jar:?]
    at akka.stream.impl.SubReceive.apply(Transfer.scala:12) ~[akka-stream_2.11-2.4.17.jar:?]
    at scala.PartialFunction$class.applyOrElse(PartialFunction.scala:123) ~[scala-library-2.11.8.jar:?]
    at akka.stream.impl.SubReceive.applyOrElse(Transfer.scala:12) ~[akka-stream_2.11-2.4.17.jar:?]
    at scala.PartialFunction$OrElse.applyOrElse(PartialFunction.scala:170) ~[scala-library-2.11.8.jar:?]
    at akka.actor.Actor$class.aroundReceive(Actor.scala:497) ~[akka-actor_2.11-2.4.17.jar:?]
    at akka.stream.impl.io.TLSActor.aroundReceive(TLSActor.scala:48) ~[akka-stream_2.11-2.4.17.jar:?]
    at akka.actor.ActorCell.receiveMessage(ActorCell.scala:526) ~[akka-actor_2.11-2.4.17.jar:?]
    at akka.actor.ActorCell.invoke(ActorCell.scala:495) ~[akka-actor_2.11-2.4.17.jar:?]
    at akka.dispatch.Mailbox.processMailbox(Mailbox.scala:257) ~[akka-actor_2.11-2.4.17.jar:?]
    at akka.dispatch.Mailbox.run(Mailbox.scala:224) ~[akka-actor_2.11-2.4.17.jar:?]
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) ~[?:1.8.0_131]
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) ~[?:1.8.0_131]
    at java.lang.Thread.run(Thread.java:748) ~[?:1.8.0_131]
Caused by: javax.net.ssl.SSLHandshakeException: General SSLEngine problem
    at sun.security.ssl.Alerts.getSSLException(Alerts.java:192) ~[?:1.8.0_131]
    at sun.security.ssl.SSLEngineImpl.fatal(SSLEngineImpl.java:1728) ~[?:1.8.0_131]
    at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:304) ~[?:1.8.0_131]
    at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:296) ~[?:1.8.0_131]
    at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1514) ~[?:1.8.0_131]
    at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:216) ~[?:1.8.0_131]
    at sun.security.ssl.Handshaker.processLoop(Handshaker.java:1026) ~[?:1.8.0_131]
    at sun.security.ssl.Handshaker$1.run(Handshaker.java:966) ~[?:1.8.0_131]
    at sun.security.ssl.Handshaker$1.run(Handshaker.java:963) ~[?:1.8.0_131]
    at java.security.AccessController.doPrivileged(Native Method) ~[?:1.8.0_131]
    at sun.security.ssl.Handshaker$DelegatedTask.run(Handshaker.java:1416) ~[?:1.8.0_131]
    at akka.stream.impl.io.TLSActor.runDelegatedTasks(TLSActor.scala:402) ~[akka-stream_2.11-2.4.17.jar:?]
    at akka.stream.impl.io.TLSActor.akka$stream$impl$io$TLSActor$$doUnwrap(TLSActor.scala:371) ~[akka-stream_2.11-2.4.17.jar:?]
    ... 24 more
Caused by: java.security.cert.CertificateException: No subject alternative names present
    at sun.security.util.HostnameChecker.matchIP(HostnameChecker.java:144) ~[?:1.8.0_131]
    at sun.security.util.HostnameChecker.match(HostnameChecker.java:93) ~[?:1.8.0_131]
    at sun.security.ssl.X509TrustManagerImpl.checkIdentity(X509TrustManagerImpl.java:455) ~[?:1.8.0_131]
    at sun.security.ssl.X509TrustManagerImpl.checkIdentity(X509TrustManagerImpl.java:436) ~[?:1.8.0_131]
    at sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:252) ~[?:1.8.0_131]
    at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:136) ~[?:1.8.0_131]
    at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1501) ~[?:1.8.0_131]
    at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:216) ~[?:1.8.0_131]
    at sun.security.ssl.Handshaker.processLoop(Handshaker.java:1026) ~[?:1.8.0_131]
    at sun.security.ssl.Handshaker$1.run(Handshaker.java:966) ~[?:1.8.0_131]
    at sun.security.ssl.Handshaker$1.run(Handshaker.java:963) ~[?:1.8.0_131]
    at java.security.AccessController.doPrivileged(Native Method) ~[?:1.8.0_131]
    at sun.security.ssl.Handshaker$DelegatedTask.run(Handshaker.java:1416) ~[?:1.8.0_131]
    at akka.stream.impl.io.TLSActor.runDelegatedTasks(TLSActor.scala:402) ~[akka-stream_2.11-2.4.17.jar:?]
    at akka.stream.impl.io.TLSActor.akka$stream$impl$io$TLSActor$$doUnwrap(TLSActor.scala:371) ~[akka-stream_2.11-2.4.17.jar:?]

一些讨论发生了here,另一个解决方案herehere,但对我和一个未完成的讨论here没有用。提出了一个解决方案here,但不确定如何为akka-http实现相同的解决方案。 几个相关的链接:

akka-issue

Configuring Trust Stores

SO Question1

SO Question 2

Solution in Java

之前我只是使用以下来执行它:

Http().superPool[MyTracker]()

我也尝试过关注,从herehere获取灵感,但问题仍然存在:

    val badSslConfig = AkkaSSLConfig().mapSettings(s => s.withLoose(s.loose.withAcceptAnyCertificate(true)))
    val badCtx = Http().createClientHttpsContext(badSslConfig)
    Http().superPool[MyTracker]()(httpMat)

编辑#1

我又添加了一个标记,但错误与之前不同:

    val badSslConfig = AkkaSSLConfig().mapSettings(s => s.withLoose(s.loose.withAcceptAnyCertificate(true).withDisableHostnameVerification(true)))
    val badCtx = Http().createClientHttpsContext(badSslConfig)
    Http().superPool[MyTracker]()(httpMat)

错误:

Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
    at sun.security.provider.certpath.SunCertPathBuilder.build(SunCertPathBuilder.java:141) ~[?:1.8.0_131]
    at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:126) ~[?:1.8.0_131]
    at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:280) ~[?:1.8.0_131]
    at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:382) ~[?:1.8.0_131]
    at sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:292) ~[?:1.8.0_131]
    at sun.security.validator.Validator.validate(Validator.java:260) ~[?:1.8.0_131]

编辑#2

answer获取灵感,不确定如何使用akka-httlp完全实现,我尝试了以下内容:

val trustStoreConfig = TrustStoreConfig(None, Some("/Users/user/path/my.cer")).withStoreType("PEM")
val trustManagerConfig = TrustManagerConfig().withTrustStoreConfigs(List(trustStoreConfig))

val sslConfig = AkkaSSLConfig().mapSettings { s =>
  s.withHostnameVerifierClass(classOf[DisabledComplainingHostnameVerifier])
  s.withTrustManagerConfig(trustManagerConfig)
  s
}
val badCtx = Http().createClientHttpsContext(sslConfig)
Http().superPool[RequestTracker](badCtx)(httpMat)

但仍然收到此错误:

  

引起:java.security.cert.CertificateException:没有主题替代名称出现

     

at sun.security.util.HostnameChecker.matchIP(HostnameChecker.java:144)〜[?:1.8.0_131]

     

at sun.security.util.HostnameChecker.match(HostnameChecker.java:93)〜[?:1.8.0_131]

     

at sun.security.ssl.X509TrustManagerImpl.checkIdentity(X509TrustManagerImpl.java:455)〜[?:1.8.0_131]

     

at sun.security.ssl.X509TrustManagerImpl.checkIdentity(X509TrustManagerImpl.java:436)〜[?:1.8.0_131]       在sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:252)〜[?:1.8.0_131]

     

at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:136)〜[?:1.8.0_131]

     

at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1501)~ [?:1.8.0_131]

在Akka中这不可能吗?

1 个答案:

答案 0 :(得分:0)

最后,从这个answer获取灵感,这似乎很复杂,下面的代码片段就可以了:

val trustStoreConfig = TrustStoreConfig(None, Some("/etc/Project/keystore/my.cer")).withStoreType("PEM")
val trustManagerConfig = TrustManagerConfig().withTrustStoreConfigs(List(trustStoreConfig))

val badSslConfig = AkkaSSLConfig().mapSettings(s => s.withLoose(s.loose
  .withAcceptAnyCertificate(true)
  .withDisableHostnameVerification(true)
).withTrustManagerConfig(trustManagerConfig))

val badCtx = Http().createClientHttpsContext(badSslConfig)

Http().superPool[RequestTracker](badCtx)(httpMat)

不确定为什么它不适用于我的其他尝试,想要深入理解,如果您了解内部,请发布解释。