scala – 带有ssl-conf的Akka HTTPS(SSL)服务器
阿卡版:
> Akka 2.4.7 阿卡特点: > HTTPS Server 语言:Scala 我正在使用Akka 2.4.7的Http Server功能在不同的端口上提供多个HTTPS服务连接. 题: 我想使用Typesafe’s ssl-config库来配置每个HTTPS服务器.我该怎么做(我的尝试不成功)? 我尝试过的: 对于每个服务,我在application.conf中定义了ssl-config配置块. nexted配置的一个例子是: my-service { ssl-config = { debug { all = true } sslParameters { clientAuth : "none" } ssl = { keyManager = { stores = [ {path: tmp/certs/autumn/devhost.jks,password: "not-real-password",type: "JKS"} ] } } } } 我使用application.conf中定义的my-service的HOCON路径来获取配置的这一部分,并将其与参考默认配置合并以创建SSLConfigSettings. def parseSslConfig(config: Config): SSLConfigSettings = { val cfg = config.withFallback(ConfigFactory.defaultReference().getConfig("ssl-config")) val parser = new SSLConfigParser(EnrichedConfig(cfg),getClass.getClassLoader) parser.parse() } 现在有一个SSLConfigSettings我现在可以创建一个AkkaSSLConfig对象,而在Akka 2.4.7中,可以使用函数原型创建一个HttpsConnectionContext: //#HTTPS的背景下创作 因此,我可以使用以下代码启动HTTPS服务器(注意:请求handeler在其他地方定义,提供Future [HttpResponse]) val akkaSSLConfig: AkkaSSLConfig = AkkaSSLConfig().withSettings(sslConfigSettings) val serverConnectionContext = ConnectionContext.https(SSLContext.getDefault,Some(akkaSSLConfig)) val httpServer = httpServerSystem.bind(interface = "127.0.0.1",port = 8991,connectionContext = serverConnectionContext) val bindingFuture: Future[Http.ServerBinding] = httpServer.to(Sink.foreach { connection => system.log.info(s"Accepted HTTP connection " + s"[Local: address=${connection.localAddress.getAddress.getHostAddress},port=${connection.localAddress.getPort};" + s" Remote: address=${connection.remoteAddress.getAddress.getHostAddress} port=${connection.remoteAddress.getPort}]" + connection.remoteAddress) connection.handleWithAsyncHandler(httpRequest => requestHandler(httpRequest,connection.localAddress,connection.remoteAddress)) }).run() 服务器无异常或错误启动,并在定义的端口8991上绑定到127.0.0.1. 2016-06-11 14:07:51,403 DEBUG [autumn-backend-akka.actor.default-dispatcher-7] TcpListener - Successfully bound to /127.0.0.1:8991 2016-06-11 14:07:51,404 DEBUG [autumn-backend-akka.actor.default-dispatcher-7] TcpListener - started (akka.io.TcpListener@3d1d819f) 2016-06-11 14:07:51,404 DEBUG [autumn-backend-akka.actor.default-dispatcher-7] TcpListener - now watched by Actor[akka://autumn-backend/system/IO-TCP/selectors/$a#-745039521] 2016-06-11 14:07:51,407 DEBUG [autumn-backend-akka.actor.default-dispatcher-5] TcpListener - now watched by Actor[akka://autumn-backend/user/StreamSupervisor-0/$$a#-672917867] 我使用浏览器或卷曲访问服务器,结果不好.它要求我知道错误的客户端证书,因为我已经在ssl-conf中明确配置它们不需要它们并且JDK8中的ssl-conf设置为默认情况下不需要它. curl -v https://localhost:8991 * Rebuilt URL to: https://localhost:8991/ * Trying 127.0.0.1... * Connected to localhost (127.0.0.1) port 8991 (#0) * SSL peer handshake failed,the server most likely requires a client certificate to connect * Closing connection 0 curl: (35) SSL peer handshake failed,the server most likely requires a client certificate to connect 使用带有_s_client_选项的openssl进行的进一步调查表明,虽然知道密钥库是好的并且在其他地方工作,但没有发生SSL握手并且没有返回证书. openssl s_client -showcerts -connect localhost:8991 CONNECTED(00000003) 140735299473488:error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure:s23_clnt.c:769: --- no peer certificate available No client certificate CA names sent --- SSL handshake has read 7 bytes and written 317 bytes --- New,(NONE),Cipher is (NONE) Secure Renegotiation IS NOT supported Compression: NONE Expansion: NONE No ALPN negotiated --- Akka登录调试模式显示没有异常,并且已建立TCP连接,TLS actor启动然后立即停止. 2016-06-11 14:09:26,378 DEBUG [autumn-backend-akka.actor.default-dispatcher-6] TcpListener - New connection accepted 2016-06-11 14:09:26,378 DEBUG [autumn-backend-akka.actor.default-dispatcher-9] SelectionHandler - now supervising Actor[akka://autumn-backend/system/IO-TCP/selectors/$a/9#1252313265] 2016-06-11 14:09:26,378 DEBUG [autumn-backend-akka.actor.default-dispatcher-5] TcpIncomingConnection - started (akka.io.TcpIncomingConnection@6f12f120) 2016-06-11 14:09:26,378 DEBUG [autumn-backend-akka.actor.default-dispatcher-5] TcpIncomingConnection - now watched by Actor[akka://autumn-backend/system/IO-TCP/selectors/$a#-745039521] 2016-06-11 14:09:26,381 INFO [autumn-backend-akka.actor.default-dispatcher-7] ActorSystemImpl - Accepted HTTP connection [Local: address=127.0.0.1,port=8991; Remote: address=127.0.0.1 port=58726]/127.0.0.1:58726 2016-06-11 14:09:26,384 DEBUG [autumn-backend-akka.actor.default-dispatcher-9] StreamSupervisor - now supervising Actor[akka://autumn-backend/user/StreamSupervisor-0/flow-9-0-unknown-operation#149184815] 2016-06-11 14:09:26,385 DEBUG [autumn-backend-akka.actor.default-dispatcher-7] TcpIncomingConnection - now watched by Actor[akka://autumn-backend/user/StreamSupervisor-0/$$j#-1999211380] 2016-06-11 14:09:26,385 DEBUG [autumn-backend-akka.actor.default-dispatcher-9] ActorGraphInterpreter - started (akka.stream.impl.fusing.ActorGraphInterpreter@57451dc8) 2016-06-11 14:09:26,385 DEBUG [autumn-backend-akka.actor.default-dispatcher-5] StreamSupervisor - now supervising Actor[akka://autumn-backend/user/StreamSupervisor-0/flow-9-1-unknown-operation#1511230856] sslConfig.config.loose.disableSNI = false 2016-06-11 14:09:26,387 DEBUG [autumn-backend-akka.actor.default-dispatcher-5] TLSActor - started (akka.stream.impl.io.TLSActor@50f220e8) 2016-06-11 14:09:26,389 DEBUG [autumn-backend-akka.actor.default-dispatcher-5] TLSActor - stopped 在运行时调试显示正在拾取密钥库: akkaSSLConfig = {com.typesafe.sslconfig.akka.AkkaSSLConfig@7851} system = {akka.actor.ActorSystemImpl@7850} "akka://autumn-backend" config = {com.typesafe.sslconfig.ssl.SSLConfigSettings@7849} "SSLConfig(None,SSLDebugConfig(false,false,None,false),Vector(RSA keySize < 2048,DSA keySize < 2048,EC keySize < 224),Vector(MD2,MD4,MD5),Some(Vector(TLSv1.2,TLSv1.1,TLSv1)),class com.typesafe.sslconfig.ssl.DefaultHostnameVerifier,KeyManagerConfig(SunX509,List(KeyStoreConfig(None,Some(config/certs/autumn/devhost.jks),Some(A8C7B78Ymb),JKS))),SSLLooseConfig(false,TLSv1.2,SSLParametersConfig(Default,Vector()),TrustManagerConfig(PKIX,List()))" default = false protocol = "TLSv1.2" checkRevocation = {scala.None$@7905} "None" revocationLists = {scala.None$@7905} "None" enabledCipherSuites = {scala.None$@7905} "None" enabledProtocols = {scala.Some@7906} "Some(Vector(TLSv1.2,TLSv1))" disabledSignatureAlgorithms = {scala.collection.immutable.Vector@7907} "Vector" size = 3 disabledKeyAlgorithms = {scala.collection.immutable.Vector@7911} "Vector" size = 3 sslParametersConfig = {com.typesafe.sslconfig.ssl.SSLParametersConfig@7917} "SSLParametersConfig(Default,Vector())" keyManagerConfig = {com.typesafe.sslconfig.ssl.KeyManagerConfig@7918} "KeyManagerConfig(SunX509,JKS)))" algorithm = "SunX509" keyStoreConfigs = {scala.collection.immutable.$colon$colon@7942} "::" size = 1 0 = {com.typesafe.sslconfig.ssl.KeyStoreConfig@9390} "KeyStoreConfig(None,Some(not-real-password),JKS)" 如果我手动创建一个HttpsConnectionContext并且不使用ssl-conf或AkkaSSLConfig – 那不是目标.如何使用AkkaSSLconf对象和Typesafe ssl-config库配置和创建HTTPS配置连接? 更新1: 如果我特别要求TLS上下文的TLS实例,如下所示: val sslCtx = SSLContext.getInstance("TLS") 我得到一个异常,即sslContext没有初始化.但是为了初始化SSLContext,我需要创建密钥库,信任库,这一切都很好,但感觉我忽略了已经定义了所有这些东西的ssl-conf库的所有优点. 更新2: 我发现您可以使用以下方法创建HTTPS连接上下文: Http().createServerHttpsContext(akkaSSLConfig) 您可以使用AkkaSSLConfig创建HTTPS服务器上下文,这是我追求的好东西.问题在于测试HTTPS服务器不起作用,它只挂起1分钟,但有异常: 2016-06-12 11:14:53,222 DEBUG [autumn-backend-akka.actor.default-dispatcher-12] RepointableActorRef - Aborting tcp connection because of upstream failure: No elements passed in the last 1 minute. akka.stream.impl.Timers$IdleTimeoutBidi$$anon$7.onTimer(Timers.scala:160) akka.stream.stage.TimerGraphStageLogic.akka$stream$stage$TimerGraphStageLogic$$onInternalTimer(GraphStage.scala:1125) akka.stream.stage.TimerGraphStageLogic$$anonfun$akka$stream$stage$TimerGraphStageLogic$$getTimerAsyncCallback$1.apply(GraphStage.scala:1114) akka.stream.stage.TimerGraphStageLogic$$anonfun$akka$stream$stage$TimerGraphStageLogic$$getTimerAsyncCallback$1.apply(GraphStage.scala:1114) akka.stream.impl.fusing.GraphInterpreter.runAsyncInput(GraphInterpreter.scala:572) akka.stream.impl.fusing.GraphInterpreterShell.receive(ActorGraphInterpreter.scala:420) akka.stream.impl.fusing.ActorGraphInterpreter.akka$stream$impl$fusing$ActorGraphInterpreter$$processEvent(ActorGraphInterpreter.scala:604) akka.stream.impl.fusing.ActorGraphInterpreter$$anonfun$receive$1.applyOrElse(ActorGraphInterpreter.scala:619) akka.actor.Actor$class.aroundReceive(Actor.scala:484) 我在GitHub here的Akka repo上查看了createServerHttpsContext的源代码,发现: // currently the same configuration as client by default,however we should tune this for server-side apropriately (!) def createServerHttpsContext(sslConfig: AkkaSSLConfig): HttpsConnectionContext = { log.warning("Automatic server-side configuration is not supported yet,will attempt to use client-side settings. " + "Instead it is recommended to construct the Servers HttpsConnectionContext manually (via SSLContext).") createClientHttpsContext(sslConfig) } 为什么HTTPS服务器不能与createServerHttpsContext(..)一起使用?特别是考虑到手动你基本上设置了一个TLS SSLContext,KeyManagerFactory(带有密钥存储区),一个SecureRandom实例,然后关闭. 解决方法
正如其他评论中所述,有一个git hub问题,表明尚不支持“自动”使用配置.但是,这个问题现在已经结束;没有完成只是
moved.我浏览了未来版本的发行说明,但我没有看到任何与此相关的内容.现在非常强调安全性,我很惊讶SSL / TSL的设置不是开箱即用的.
我正在使用v2.4.4(当前是2.4.16)和提问者类似,我发现了很难的方法虽然akk-http文档告诉你使用配置,实际上从调试你可以看到配置得到读入,实际使用它的实现,没有完成.我在日志中收到此消息: akka.actor.ActorSystemImpl(OtisRestActorSystem)] Automatic server-side configuration is not supported yet,will attempt to use client-side settings. Instead it is recommended to construct the Servers HttpsConnectionContext manually (via SSLContext) 我尝试使用他们的ssl配置“手动构建服务器HttpsConnectionContext”,但我无法让它工作. 还有其他消息,当我最初进行故障排除时显示它在配置的密钥存储区中读取(它不使用类路径来查找它,因此它最初无法找到它).因此,我不确定哪些部件正在工作,哪些部件缺失.所以我最终完全放弃了akka-http ssl配置并自己设置,因为我的用例非常简单.我只想启用服务器端SSL / TSL. 在我的配置中,我有: ssl { keyStoreFileName = "myKeyFile.p12" keyStorePassword = "myPassword" } 为了阅读我的设置,我有: class Settings(config: Config) extends Extension { object Ssl { var KeyStoreFileName = config.getString("ssl.keyStoreFileName") var KeyStorePassword = config.getString("ssl.keyStorePassword") } } 而对于“App”,我有: object RestWebServiceApp extends App with RouteConcatenation { import akka.event.{Logging,LoggingAdapter} import akka.http.scaladsl.{ ConnectionContext,HttpsConnectionContext,Http } import akka.http.scaladsl.server.Directives._ import akka.http.scaladsl.model.MediaTypes._ import akka.stream.{ActorMaterializer,ActorMaterializerSettings} import java.io.InputStream import java.security.{ SecureRandom,KeyStore } import javax.net.ssl.{ SSLContext,TrustManagerFactory,KeyManagerFactory } import JsonSupport._ implicit val system = ActorSystem("OtisRestActorSystem") implicit val materializer: ActorMaterializer = ActorMaterializer(ActorMaterializerSettings(system)) implicit val ec = system.dispatcher ... //setting up all the routes,etc. val settings = Settings(system) val fileName = settings.Ssl.KeyStoreFileName val keyFile: InputStream = getClass.getClassLoader.getResourceAsStream(fileName) require(keyFile != null,s"Failed to load key file: ${settings.Ssl.KeyStoreFileName}") val extension = if(fileName.lastIndexOf('.')>0) fileName.substring(fileName.lastIndexOf('.')+1) else "" val keyStore: KeyStore = extension.toLowerCase match { case "jks" => KeyStore.getInstance("jks") //Java Key Store; Java default and only works with Java; tested case "jcek" => KeyStore.getInstance("JCEKS") //Java Cryptography Extension KeyStore; Java 1.4+; not tested case "pfx" | "p12" => KeyStore.getInstance("PKCS12") // PKCS #12,Common and supported by many languages/frameworks; tested case _ => throw new IllegalArgumentException(s"Key has an unknown type extension $extension. Support types are jks,jcek,pfx,p12.") } val password: Array[Char] = (if(settings.Ssl.KeyStorePassword==null) "" else settings.Ssl.KeyStorePassword).toCharArray keyStore.load(keyFile,password) //TODO: looks like the "SunX509","TLS",are defined in the keystore,should we pull them out rather than hard coding? val keyManagerFactory: KeyManagerFactory = KeyManagerFactory.getInstance("SunX509") keyManagerFactory.init(keyStore,password) val tmf: TrustManagerFactory = TrustManagerFactory.getInstance("SunX509") tmf.init(keyStore) val sslContext: SSLContext = SSLContext.getInstance("TLS") sslContext.init(keyManagerFactory.getKeyManagers,tmf.getTrustManagers,new SecureRandom) val https: HttpsConnectionContext = ConnectionContext.https(sslContext) Http().setDefaultServerHttpContext(https) Http().bindAndHandle(routes,"localhost",433,connectionContext = https) } (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |