具有非HTTP TCP服务器的Lightbend ssl-config

时间:2018-08-28 05:42:33

标签: scala ssl akka

我发现了一些资源,这些资源提供了有关在application.conf文件中配置ssl-config选项的详细信息,并且已经确定了如何使用AkkaSSLConfig.get()访问这些配置。我已经看到可以使用AkkaSSLConfig对象作为ConnectionContext.https()的参数来创建https上下文。

是否可以将其用于非HTTP服务器?返回的上下文是否以某种方式特定于http?我正在尝试利用ssl-config的优势,但我不清楚它是否可以为非http服务器提供任何优势,而且我看不到任何从ssl-config定义中构建上下文的便捷方法,在这种情况下,我似乎还可以手动定义上下文。

最后,很难找到为非http服务器构建上下文的任何示例。看来该过程可能与http服务器相同,但是我发现示例经常包括使用名称中带有“ http”的类/方法。如果有人知道一个好榜样,我将不胜感激。

2 个答案:

答案 0 :(得分:0)

import java.io.{File, FileInputStream}
import java.security.{KeyStore, SecureRandom}
import akka.actor.ActorSystem
import akka.http.scaladsl.Http.ServerBinding
import akka.http.scaladsl.model.{HttpResponse, StatusCodes}
import akka.http.scaladsl.server.Directives._
import akka.http.scaladsl.server.Route
import akka.http.scaladsl.server.Directives.pathSingleSlash
import akka.http.scaladsl.{ConnectionContext, Http}
import akka.stream.{ActorMaterializer, TLSClientAuth}
import com.typesafe.sslconfig.akka.AkkaSSLConfig
import com.typesafe.sslconfig.ssl.{KeyManagerConfig, KeyManagerFactoryWrapper, KeyStoreConfig, SSLConfigFactory, SSLConfigSettings}
import javax.net.ssl.{SSLContext, TrustManagerFactory}

import scala.concurrent.{ExecutionContext, Future}

object Test extends App{

  implicit val actorSystem: ActorSystem = ActorSystem("test")
  implicit val materializer: ActorMaterializer = ActorMaterializer()
  implicit val executionContext: ExecutionContext = actorSystem.dispatcher

  val ksConfig: KeyStoreConfig = KeyStoreConfig.apply(data = None,
    filePath = Some("/Users/mshaik/testApp/src/main/resources/keystore/localhost.p12")
  ).withPassword(Some("test"))

  val kmConfig: KeyManagerConfig = KeyManagerConfig().withKeyStoreConfigs(List(ksConfig))

  val sslConfigSettings: SSLConfigSettings = SSLConfigFactory.defaultConfig.withKeyManagerConfig(kmConfig)

  val akkaSSLConfig: AkkaSSLConfig = AkkaSSLConfig.get(actorSystem).withSettings(sslConfigSettings)

  val ks: KeyStore = KeyStore.getInstance("PKCS12")
  ks.load(new FileInputStream(new File(ksConfig.filePath.get)), ksConfig.password.get.toCharArray)

  val kmf: KeyManagerFactoryWrapper = akkaSSLConfig.buildKeyManagerFactory(sslConfigSettings)
  kmf.init(ks, ksConfig.password.get.toCharArray)

  val tmf: TrustManagerFactory = TrustManagerFactory.getInstance("SunX509")
  tmf.init(ks)

  val sslContext: SSLContext = SSLContext.getInstance("TLS")
  sslContext.init(kmf.getKeyManagers, tmf.getTrustManagers, new SecureRandom)

  val ctx: ConnectionContext = ConnectionContext.https(sslContext,
    sslConfig = Some(akkaSSLConfig),
    clientAuth = Some(TLSClientAuth.Want)
  )

  var bindingFuture: Future[ServerBinding] = _

  Http().setDefaultServerHttpContext(ctx)

  val route: Route = pathSingleSlash {
    get {
      complete(HttpResponse(StatusCodes.OK, entity = "Welcome to base path!"))
    }
  }

  try{
    bindingFuture = Http().bindAndHandle(route,  "localhost", 8085, connectionContext = ctx)
    println( s"Server online at https://localhost:8085/")
  } catch {
    case ex: Exception =>
      println(this.getClass, ex.getMessage, ex)
      materializer.shutdown()
      actorSystem.terminate()
  }
}

答案 1 :(得分:0)

我相信我的问题的答案是,在创建非HTTP TLS连接时,在ssl-config中彻底配置TLS选项并没有多大用处。

我发现的一个示例都没有显示如何在配置中定义密钥库和信任库参数,然后使用这些配置来创建SSLContext对象(所有示例都在代码内手动配置密钥库/信任库参数)。最终,我发现使用ssl-config来存储配置没有用。我发现它唯一有用的地方是获取默认密码和默认协议的列表(因此我仍在代码中使用它)。

作为参考,下面是我最终配置上下文和初始会话结构并创建TCP服务器的操作。这与文档中的其他示例以及此处的一些响应非常相似。此响应中的某些区别:1)这需要客户端证书,2)这是针对服务器(而不是客户端)的,3)此代码显示了如何使用工厂方法来创建TLS BidiFlow(请注意{{1} }通话)4)这允许您传递将处理传入通信的Flow。

Tcp().bindTls