sss.openstar.http.TLSWebSocketServer.scala Maven / Gradle / Ivy
package sss.openstar.http
import akka.actor.ActorSystem
import akka.http.scaladsl.server.Route
import akka.http.scaladsl.{ConnectionContext, Http, HttpsConnectionContext}
import com.typesafe.config.Config
import sss.ancillary.Logging
import sss.openstar.http.TLSWebSocketServer.TLSWebSocketServerConfig
import java.io.{File, FileInputStream, InputStream}
import java.security.{KeyStore, SecureRandom}
import javax.net.ssl.{KeyManagerFactory, SSLContext, TrustManagerFactory}
import scala.concurrent.ExecutionContext.Implicits.global
import scala.util.{Failure, Success}
object TLSWebSocketServer {
case class TLSWebSocketServerConfig(
httpsEnabled: Boolean,
keyStorePassword: String,
keyStorePath: String,
bindToIp: String,
bindToPort: Int,
keyStoreType: String = "PKCS12",
keyFactoryType:String = "SunX509")
def apply(route: Route, config: Config)(implicit actorSystem: ActorSystem): TLSWebSocketServer = {
val c = TLSWebSocketServerConfig(
config.getBoolean("httpsEnabled"),
config.getString("keyStorePassword"),
config.getString("keyStorePath"),
config.getString("bindToIp"),
config.getInt("bindToPort"),
config.getString("keyStoreType"),
config.getString("keyFactoryType")
)
new TLSWebSocketServer(route, c)
}
}
class TLSWebSocketServer(
route: Route,
tlsConfig: TLSWebSocketServerConfig,
)(implicit actorSystem: ActorSystem) extends Logging {
import tlsConfig._
private lazy val password: Array[Char] = keyStorePassword.toCharArray
private lazy val ks: KeyStore = KeyStore.getInstance(keyStoreType)
private lazy val keystore: InputStream = {
val attempt1 = new FileInputStream(new File(keyStorePath))
Option(attempt1).getOrElse {
val attempt2 = getClass.getClassLoader.getResourceAsStream(keyStorePath)
Option(attempt2).getOrElse(
throw new IllegalArgumentException(s"Cannot load keystore $keyStorePath")
)
}
}
ks.load(keystore, password)
private lazy val keyManagerFactory: KeyManagerFactory = KeyManagerFactory.getInstance(keyFactoryType) // "SunX509"
keyManagerFactory.init(ks, password)
private lazy val tmf: TrustManagerFactory = TrustManagerFactory.getInstance(keyFactoryType) // "SunX509"
tmf.init(ks)
private lazy val sslContext: SSLContext = SSLContext.getInstance("TLS")
sslContext.init(keyManagerFactory.getKeyManagers, tmf.getTrustManagers, new SecureRandom)
private lazy val https: HttpsConnectionContext = ConnectionContext.httpsServer(sslContext)
lazy val start = if(httpsEnabled) {
Http()
.newServerAt(bindToIp, bindToPort)
.enableHttps(https)
.bindFlow(route)
} else {
Http()
.newServerAt(bindToIp, bindToPort)
.bindFlow(route)
}.onComplete {
case Success(value) => log.info(value.toString)
case Failure(err) => log.error(err.toString)
}
}