This commit is contained in:
parent
c75504c3b6
commit
b9ce2c94f6
10 changed files with 175 additions and 47 deletions
|
|
@ -9,6 +9,7 @@ import akka.http.scaladsl
|
||||||
import akka.japi.Util
|
import akka.japi.Util
|
||||||
import akka.stream.TLSClientAuth
|
import akka.stream.TLSClientAuth
|
||||||
import akka.http.impl.util.JavaMapping.Implicits._
|
import akka.http.impl.util.JavaMapping.Implicits._
|
||||||
|
import com.typesafe.sslconfig.akka.AkkaSSLConfig
|
||||||
|
|
||||||
import scala.compat.java8.OptionConverters
|
import scala.compat.java8.OptionConverters
|
||||||
import scala.collection.JavaConverters._
|
import scala.collection.JavaConverters._
|
||||||
|
|
@ -21,6 +22,23 @@ object ConnectionContext {
|
||||||
scaladsl.ConnectionContext.https(sslContext)
|
scaladsl.ConnectionContext.https(sslContext)
|
||||||
|
|
||||||
/** Used to serve HTTPS traffic. */
|
/** Used to serve HTTPS traffic. */
|
||||||
|
def https(sslContext: SSLContext,
|
||||||
|
sslConfig: Optional[AkkaSSLConfig],
|
||||||
|
enabledCipherSuites: Optional[JCollection[String]],
|
||||||
|
enabledProtocols: Optional[JCollection[String]],
|
||||||
|
clientAuth: Optional[TLSClientAuth],
|
||||||
|
sslParameters: Optional[SSLParameters]) =
|
||||||
|
scaladsl.ConnectionContext.https(
|
||||||
|
sslContext,
|
||||||
|
OptionConverters.toScala(sslConfig),
|
||||||
|
OptionConverters.toScala(enabledCipherSuites).map(Util.immutableSeq(_)),
|
||||||
|
OptionConverters.toScala(enabledProtocols).map(Util.immutableSeq(_)),
|
||||||
|
OptionConverters.toScala(clientAuth),
|
||||||
|
OptionConverters.toScala(sslParameters))
|
||||||
|
//#https-context-creation
|
||||||
|
|
||||||
|
/** Used to serve HTTPS traffic. */
|
||||||
|
// for binary-compatibility, since 2.4.7
|
||||||
def https(sslContext: SSLContext,
|
def https(sslContext: SSLContext,
|
||||||
enabledCipherSuites: Optional[JCollection[String]],
|
enabledCipherSuites: Optional[JCollection[String]],
|
||||||
enabledProtocols: Optional[JCollection[String]],
|
enabledProtocols: Optional[JCollection[String]],
|
||||||
|
|
@ -32,7 +50,6 @@ object ConnectionContext {
|
||||||
OptionConverters.toScala(enabledProtocols).map(Util.immutableSeq(_)),
|
OptionConverters.toScala(enabledProtocols).map(Util.immutableSeq(_)),
|
||||||
OptionConverters.toScala(clientAuth),
|
OptionConverters.toScala(clientAuth),
|
||||||
OptionConverters.toScala(sslParameters))
|
OptionConverters.toScala(sslParameters))
|
||||||
//#https-context-creation
|
|
||||||
|
|
||||||
/** Used to serve HTTP traffic. */
|
/** Used to serve HTTP traffic. */
|
||||||
def noEncryption(): HttpConnectionContext =
|
def noEncryption(): HttpConnectionContext =
|
||||||
|
|
@ -43,11 +60,13 @@ abstract class ConnectionContext {
|
||||||
def isSecure: Boolean
|
def isSecure: Boolean
|
||||||
/** Java API */
|
/** Java API */
|
||||||
def getDefaultPort: Int
|
def getDefaultPort: Int
|
||||||
|
def sslConfig: Option[AkkaSSLConfig]
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class HttpConnectionContext extends akka.http.javadsl.ConnectionContext {
|
abstract class HttpConnectionContext extends akka.http.javadsl.ConnectionContext {
|
||||||
override final def isSecure = false
|
override final def isSecure = false
|
||||||
override final def getDefaultPort = 80
|
override final def getDefaultPort = 80
|
||||||
|
override def sslConfig: Option[AkkaSSLConfig] = None
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class HttpsConnectionContext extends akka.http.javadsl.ConnectionContext {
|
abstract class HttpsConnectionContext extends akka.http.javadsl.ConnectionContext {
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ package akka.http.scaladsl
|
||||||
|
|
||||||
import akka.stream.TLSClientAuth
|
import akka.stream.TLSClientAuth
|
||||||
import akka.stream.TLSProtocol._
|
import akka.stream.TLSProtocol._
|
||||||
|
import com.typesafe.sslconfig.akka.AkkaSSLConfig
|
||||||
|
|
||||||
import scala.collection.JavaConverters._
|
import scala.collection.JavaConverters._
|
||||||
import java.util.{ Optional, Collection ⇒ JCollection }
|
import java.util.{ Optional, Collection ⇒ JCollection }
|
||||||
|
|
@ -22,25 +23,43 @@ object ConnectionContext {
|
||||||
//#https-context-creation
|
//#https-context-creation
|
||||||
// ConnectionContext
|
// ConnectionContext
|
||||||
def https(sslContext: SSLContext,
|
def https(sslContext: SSLContext,
|
||||||
|
sslConfig: Option[AkkaSSLConfig] = None,
|
||||||
enabledCipherSuites: Option[immutable.Seq[String]] = None,
|
enabledCipherSuites: Option[immutable.Seq[String]] = None,
|
||||||
enabledProtocols: Option[immutable.Seq[String]] = None,
|
enabledProtocols: Option[immutable.Seq[String]] = None,
|
||||||
clientAuth: Option[TLSClientAuth] = None,
|
clientAuth: Option[TLSClientAuth] = None,
|
||||||
sslParameters: Option[SSLParameters] = None) = {
|
sslParameters: Option[SSLParameters] = None) =
|
||||||
new HttpsConnectionContext(sslContext, enabledCipherSuites, enabledProtocols, clientAuth, sslParameters)
|
new HttpsConnectionContext(sslContext, sslConfig, enabledCipherSuites, enabledProtocols, clientAuth, sslParameters)
|
||||||
}
|
|
||||||
//#https-context-creation
|
//#https-context-creation
|
||||||
|
|
||||||
|
// for binary-compatibility, since 2.4.7
|
||||||
|
def https(sslContext: SSLContext,
|
||||||
|
enabledCipherSuites: Option[immutable.Seq[String]],
|
||||||
|
enabledProtocols: Option[immutable.Seq[String]],
|
||||||
|
clientAuth: Option[TLSClientAuth],
|
||||||
|
sslParameters: Option[SSLParameters]) =
|
||||||
|
new HttpsConnectionContext(sslContext, None, enabledCipherSuites, enabledProtocols, clientAuth, sslParameters)
|
||||||
|
|
||||||
def noEncryption() = HttpConnectionContext
|
def noEncryption() = HttpConnectionContext
|
||||||
}
|
}
|
||||||
|
|
||||||
final class HttpsConnectionContext(
|
final class HttpsConnectionContext(
|
||||||
val sslContext: SSLContext,
|
val sslContext: SSLContext,
|
||||||
|
val sslConfig: Option[AkkaSSLConfig] = None,
|
||||||
val enabledCipherSuites: Option[immutable.Seq[String]] = None,
|
val enabledCipherSuites: Option[immutable.Seq[String]] = None,
|
||||||
val enabledProtocols: Option[immutable.Seq[String]] = None,
|
val enabledProtocols: Option[immutable.Seq[String]] = None,
|
||||||
val clientAuth: Option[TLSClientAuth] = None,
|
val clientAuth: Option[TLSClientAuth] = None,
|
||||||
val sslParameters: Option[SSLParameters] = None)
|
val sslParameters: Option[SSLParameters] = None)
|
||||||
extends akka.http.javadsl.HttpsConnectionContext with ConnectionContext {
|
extends akka.http.javadsl.HttpsConnectionContext with ConnectionContext {
|
||||||
|
|
||||||
|
// for binary-compatibility, since 2.4.7
|
||||||
|
def this(
|
||||||
|
sslContext: SSLContext,
|
||||||
|
enabledCipherSuites: Option[immutable.Seq[String]],
|
||||||
|
enabledProtocols: Option[immutable.Seq[String]],
|
||||||
|
clientAuth: Option[TLSClientAuth],
|
||||||
|
sslParameters: Option[SSLParameters]) =
|
||||||
|
this(sslContext, None, enabledCipherSuites, enabledProtocols, clientAuth, sslParameters)
|
||||||
|
|
||||||
def firstSession = NegotiateNewSession(enabledCipherSuites, enabledProtocols, clientAuth, sslParameters)
|
def firstSession = NegotiateNewSession(enabledCipherSuites, enabledProtocols, clientAuth, sslParameters)
|
||||||
|
|
||||||
override def getSslContext = sslContext
|
override def getSslContext = sslContext
|
||||||
|
|
|
||||||
|
|
@ -587,7 +587,7 @@ class HttpExt(private val config: Config)(implicit val system: ActorSystem) exte
|
||||||
/** Creates real or placebo SslTls stage based on if ConnectionContext is HTTPS or not. */
|
/** Creates real or placebo SslTls stage based on if ConnectionContext is HTTPS or not. */
|
||||||
private[http] def sslTlsStage(connectionContext: ConnectionContext, role: TLSRole, hostInfo: Option[(String, Int)] = None) =
|
private[http] def sslTlsStage(connectionContext: ConnectionContext, role: TLSRole, hostInfo: Option[(String, Int)] = None) =
|
||||||
connectionContext match {
|
connectionContext match {
|
||||||
case hctx: HttpsConnectionContext ⇒ TLS(hctx.sslContext, hctx.firstSession, role, hostInfo = hostInfo)
|
case hctx: HttpsConnectionContext ⇒ TLS(hctx.sslContext, connectionContext.sslConfig, hctx.firstSession, role, hostInfo = hostInfo)
|
||||||
case other ⇒ TLSPlacebo() // if it's not HTTPS, we don't enable SSL/TLS
|
case other ⇒ TLSPlacebo() // if it's not HTTPS, we don't enable SSL/TLS
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -815,7 +815,7 @@ trait DefaultSSLContextCreation {
|
||||||
defaultParams.setEndpointIdentificationAlgorithm("https")
|
defaultParams.setEndpointIdentificationAlgorithm("https")
|
||||||
}
|
}
|
||||||
|
|
||||||
new HttpsConnectionContext(sslContext, Some(cipherSuites.toList), Some(defaultProtocols.toList), clientAuth, Some(defaultParams))
|
new HttpsConnectionContext(sslContext, Some(sslConfig), Some(cipherSuites.toList), Some(defaultProtocols.toList), clientAuth, Some(defaultParams))
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import java.security.SecureRandom
|
||||||
import java.util.concurrent.TimeoutException
|
import java.util.concurrent.TimeoutException
|
||||||
|
|
||||||
import akka.NotUsed
|
import akka.NotUsed
|
||||||
|
import com.typesafe.sslconfig.akka.AkkaSSLConfig
|
||||||
|
|
||||||
import scala.collection.immutable
|
import scala.collection.immutable
|
||||||
import scala.concurrent.Await
|
import scala.concurrent.Await
|
||||||
|
|
@ -90,6 +91,8 @@ class TlsSpec extends AkkaSpec("akka.loglevel=INFO\nakka.actor.debug.receive=off
|
||||||
|
|
||||||
import GraphDSL.Implicits._
|
import GraphDSL.Implicits._
|
||||||
|
|
||||||
|
val sslConfig: Option[AkkaSSLConfig] = None // no special settings to be applied here
|
||||||
|
|
||||||
"SslTls" must {
|
"SslTls" must {
|
||||||
|
|
||||||
val sslContext = initSslContext()
|
val sslContext = initSslContext()
|
||||||
|
|
@ -103,9 +106,9 @@ class TlsSpec extends AkkaSpec("akka.loglevel=INFO\nakka.actor.debug.receive=off
|
||||||
}
|
}
|
||||||
|
|
||||||
val cipherSuites = NegotiateNewSession.withCipherSuites("TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", "TLS_RSA_WITH_AES_128_CBC_SHA")
|
val cipherSuites = NegotiateNewSession.withCipherSuites("TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", "TLS_RSA_WITH_AES_128_CBC_SHA")
|
||||||
def clientTls(closing: TLSClosing) = TLS(sslContext, cipherSuites, Client, closing)
|
def clientTls(closing: TLSClosing) = TLS(sslContext, None, cipherSuites, Client, closing)
|
||||||
def badClientTls(closing: TLSClosing) = TLS(initWithTrust("/badtruststore"), cipherSuites, Client, closing)
|
def badClientTls(closing: TLSClosing) = TLS(initWithTrust("/badtruststore"), None, cipherSuites, Client, closing)
|
||||||
def serverTls(closing: TLSClosing) = TLS(sslContext, cipherSuites, Server, closing)
|
def serverTls(closing: TLSClosing) = TLS(sslContext, None, cipherSuites, Server, closing)
|
||||||
|
|
||||||
trait Named {
|
trait Named {
|
||||||
def name: String =
|
def name: String =
|
||||||
|
|
|
||||||
|
|
@ -121,7 +121,7 @@ private[akka] case class ActorMaterializerImpl(system: ActorSystem,
|
||||||
case tls: TlsModule ⇒ // TODO solve this so TlsModule doesn't need special treatment here
|
case tls: TlsModule ⇒ // TODO solve this so TlsModule doesn't need special treatment here
|
||||||
val es = effectiveSettings(effectiveAttributes)
|
val es = effectiveSettings(effectiveAttributes)
|
||||||
val props =
|
val props =
|
||||||
TLSActor.props(es, tls.sslContext, tls.firstSession, tls.role, tls.closing, tls.hostInfo)
|
TLSActor.props(es, tls.sslContext, tls.sslConfig, tls.firstSession, tls.role, tls.closing, tls.hostInfo)
|
||||||
val impl = actorOf(props, stageName(effectiveAttributes), es.dispatcher)
|
val impl = actorOf(props, stageName(effectiveAttributes), es.dispatcher)
|
||||||
def factory(id: Int) = new ActorPublisher[Any](impl) {
|
def factory(id: Int) = new ActorPublisher[Any](impl) {
|
||||||
override val wakeUpMsg = FanOut.SubstreamSubscribePending(id)
|
override val wakeUpMsg = FanOut.SubstreamSubscribePending(id)
|
||||||
|
|
|
||||||
|
|
@ -27,12 +27,13 @@ private[akka] object TLSActor {
|
||||||
|
|
||||||
def props(settings: ActorMaterializerSettings,
|
def props(settings: ActorMaterializerSettings,
|
||||||
sslContext: SSLContext,
|
sslContext: SSLContext,
|
||||||
|
sslConfig: Option[AkkaSSLConfig],
|
||||||
firstSession: NegotiateNewSession,
|
firstSession: NegotiateNewSession,
|
||||||
role: TLSRole,
|
role: TLSRole,
|
||||||
closing: TLSClosing,
|
closing: TLSClosing,
|
||||||
hostInfo: Option[(String, Int)],
|
hostInfo: Option[(String, Int)],
|
||||||
tracing: Boolean = false): Props =
|
tracing: Boolean = false): Props =
|
||||||
Props(new TLSActor(settings, sslContext, firstSession, role, closing, hostInfo, tracing)).withDeploy(Deploy.local)
|
Props(new TLSActor(settings, sslContext, sslConfig, firstSession, role, closing, hostInfo, tracing)).withDeploy(Deploy.local)
|
||||||
|
|
||||||
final val TransportIn = 0
|
final val TransportIn = 0
|
||||||
final val TransportOut = 0
|
final val TransportOut = 0
|
||||||
|
|
@ -46,6 +47,7 @@ private[akka] object TLSActor {
|
||||||
*/
|
*/
|
||||||
private[akka] class TLSActor(settings: ActorMaterializerSettings,
|
private[akka] class TLSActor(settings: ActorMaterializerSettings,
|
||||||
sslContext: SSLContext,
|
sslContext: SSLContext,
|
||||||
|
externalSslConfig: Option[AkkaSSLConfig],
|
||||||
firstSession: NegotiateNewSession, role: TLSRole, closing: TLSClosing,
|
firstSession: NegotiateNewSession, role: TLSRole, closing: TLSClosing,
|
||||||
hostInfo: Option[(String, Int)], tracing: Boolean)
|
hostInfo: Option[(String, Int)], tracing: Boolean)
|
||||||
extends Actor with ActorLogging with Pump {
|
extends Actor with ActorLogging with Pump {
|
||||||
|
|
@ -128,24 +130,23 @@ private[akka] class TLSActor(settings: ActorMaterializerSettings,
|
||||||
|
|
||||||
// These are Netty's default values
|
// These are Netty's default values
|
||||||
// 16665 + 1024 (room for compressed data) + 1024 (for OpenJDK compatibility)
|
// 16665 + 1024 (room for compressed data) + 1024 (for OpenJDK compatibility)
|
||||||
val transportOutBuffer = ByteBuffer.allocate(16665 + 2048)
|
private val transportOutBuffer = ByteBuffer.allocate(16665 + 2048)
|
||||||
/*
|
/*
|
||||||
* deviating here: chopping multiple input packets into this buffer can lead to
|
* deviating here: chopping multiple input packets into this buffer can lead to
|
||||||
* an OVERFLOW signal that also is an UNDERFLOW; avoid unnecessary copying by
|
* an OVERFLOW signal that also is an UNDERFLOW; avoid unnecessary copying by
|
||||||
* increasing this buffer size to host up to two packets
|
* increasing this buffer size to host up to two packets
|
||||||
*/
|
*/
|
||||||
val userOutBuffer = ByteBuffer.allocate(16665 * 2 + 2048)
|
private val userOutBuffer = ByteBuffer.allocate(16665 * 2 + 2048)
|
||||||
val transportInBuffer = ByteBuffer.allocate(16665 + 2048)
|
private val transportInBuffer = ByteBuffer.allocate(16665 + 2048)
|
||||||
val userInBuffer = ByteBuffer.allocate(16665 + 2048)
|
private val userInBuffer = ByteBuffer.allocate(16665 + 2048)
|
||||||
|
|
||||||
val userInChoppingBlock = new ChoppingBlock(UserIn, "UserIn")
|
private val userInChoppingBlock = new ChoppingBlock(UserIn, "UserIn")
|
||||||
userInChoppingBlock.prepare(userInBuffer)
|
userInChoppingBlock.prepare(userInBuffer)
|
||||||
val transportInChoppingBlock = new ChoppingBlock(TransportIn, "TransportIn")
|
private val transportInChoppingBlock = new ChoppingBlock(TransportIn, "TransportIn")
|
||||||
transportInChoppingBlock.prepare(transportInBuffer)
|
transportInChoppingBlock.prepare(transportInBuffer)
|
||||||
|
|
||||||
// ssl-config
|
private val sslConfig = externalSslConfig.getOrElse(AkkaSSLConfig(context.system))
|
||||||
val sslConfig = AkkaSSLConfig(context.system)
|
private val hostnameVerifier = sslConfig.hostnameVerifier
|
||||||
val hostnameVerifier = sslConfig.hostnameVerifier
|
|
||||||
|
|
||||||
val engine: SSLEngine = {
|
val engine: SSLEngine = {
|
||||||
val e = hostInfo match {
|
val e = hostInfo match {
|
||||||
|
|
@ -473,25 +474,28 @@ private[akka] class TLSActor(settings: ActorMaterializerSettings,
|
||||||
// since setting a custom HostnameVerified (in JDK8, update 60 still) disables SNI
|
// since setting a custom HostnameVerified (in JDK8, update 60 still) disables SNI
|
||||||
// see here: https://docs.oracle.com/javase/8/docs/technotes/guides/security/jsse/JSSERefGuide.html#SNIExamples
|
// see here: https://docs.oracle.com/javase/8/docs/technotes/guides/security/jsse/JSSERefGuide.html#SNIExamples
|
||||||
// resolves: https://github.com/akka/akka/issues/19287
|
// resolves: https://github.com/akka/akka/issues/19287
|
||||||
private def applySNI(params: NegotiateNewSession): Unit = for {
|
private def applySNI(params: NegotiateNewSession): Unit = {
|
||||||
sslParams ← params.sslParameters
|
println("sslConfig.config.loose.disableSNI = " + sslConfig.config.loose.disableSNI)
|
||||||
(hostname, _) ← hostInfo
|
for {
|
||||||
if !sslConfig.config.loose.disableSNI
|
sslParams ← params.sslParameters
|
||||||
} yield {
|
(hostname, _) ← hostInfo
|
||||||
// first copy the *mutable* SLLParameters before modifying to prevent race condition in `setServerNames`
|
if !sslConfig.config.loose.disableSNI
|
||||||
val clone = new SSLParameters()
|
} yield {
|
||||||
clone.setCipherSuites(sslParams.getCipherSuites)
|
// first copy the *mutable* SLLParameters before modifying to prevent race condition in `setServerNames`
|
||||||
clone.setProtocols(sslParams.getProtocols)
|
val clone = new SSLParameters()
|
||||||
clone.setWantClientAuth(sslParams.getWantClientAuth)
|
clone.setCipherSuites(sslParams.getCipherSuites)
|
||||||
clone.setNeedClientAuth(sslParams.getNeedClientAuth)
|
clone.setProtocols(sslParams.getProtocols)
|
||||||
clone.setEndpointIdentificationAlgorithm(sslParams.getEndpointIdentificationAlgorithm)
|
clone.setWantClientAuth(sslParams.getWantClientAuth)
|
||||||
clone.setAlgorithmConstraints(sslParams.getAlgorithmConstraints)
|
clone.setNeedClientAuth(sslParams.getNeedClientAuth)
|
||||||
clone.setSNIMatchers(sslParams.getSNIMatchers)
|
clone.setEndpointIdentificationAlgorithm(sslParams.getEndpointIdentificationAlgorithm)
|
||||||
clone.setUseCipherSuitesOrder(sslParams.getUseCipherSuitesOrder)
|
clone.setAlgorithmConstraints(sslParams.getAlgorithmConstraints)
|
||||||
|
clone.setSNIMatchers(sslParams.getSNIMatchers)
|
||||||
|
clone.setUseCipherSuitesOrder(sslParams.getUseCipherSuitesOrder)
|
||||||
|
|
||||||
// apply the changes
|
// apply the changes
|
||||||
clone.setServerNames(Collections.singletonList(new SNIHostName(hostname)))
|
clone.setServerNames(Collections.singletonList(new SNIHostName(hostname)))
|
||||||
engine.setSSLParameters(clone)
|
engine.setSSLParameters(clone)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ import akka.stream._
|
||||||
import akka.stream.impl.StreamLayout.{ CompositeModule, AtomicModule }
|
import akka.stream.impl.StreamLayout.{ CompositeModule, AtomicModule }
|
||||||
import akka.stream.TLSProtocol._
|
import akka.stream.TLSProtocol._
|
||||||
import akka.util.ByteString
|
import akka.util.ByteString
|
||||||
|
import com.typesafe.sslconfig.akka.AkkaSSLConfig
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* INTERNAL API.
|
* INTERNAL API.
|
||||||
|
|
@ -14,12 +15,13 @@ private[akka] final case class TlsModule(plainIn: Inlet[SslTlsOutbound], plainOu
|
||||||
cipherIn: Inlet[ByteString], cipherOut: Outlet[ByteString],
|
cipherIn: Inlet[ByteString], cipherOut: Outlet[ByteString],
|
||||||
shape: Shape, attributes: Attributes,
|
shape: Shape, attributes: Attributes,
|
||||||
sslContext: SSLContext,
|
sslContext: SSLContext,
|
||||||
|
sslConfig: Option[AkkaSSLConfig],
|
||||||
firstSession: NegotiateNewSession,
|
firstSession: NegotiateNewSession,
|
||||||
role: TLSRole, closing: TLSClosing, hostInfo: Option[(String, Int)]) extends AtomicModule {
|
role: TLSRole, closing: TLSClosing, hostInfo: Option[(String, Int)]) extends AtomicModule {
|
||||||
|
|
||||||
override def withAttributes(att: Attributes): TlsModule = copy(attributes = att)
|
override def withAttributes(att: Attributes): TlsModule = copy(attributes = att)
|
||||||
override def carbonCopy: TlsModule =
|
override def carbonCopy: TlsModule =
|
||||||
TlsModule(attributes, sslContext, firstSession, role, closing, hostInfo)
|
TlsModule(attributes, sslContext, sslConfig, firstSession, role, closing, hostInfo)
|
||||||
|
|
||||||
override def replaceShape(s: Shape) =
|
override def replaceShape(s: Shape) =
|
||||||
if (s != shape) {
|
if (s != shape) {
|
||||||
|
|
@ -34,13 +36,13 @@ private[akka] final case class TlsModule(plainIn: Inlet[SslTlsOutbound], plainOu
|
||||||
* INTERNAL API.
|
* INTERNAL API.
|
||||||
*/
|
*/
|
||||||
private[akka] object TlsModule {
|
private[akka] object TlsModule {
|
||||||
def apply(attributes: Attributes, sslContext: SSLContext, firstSession: NegotiateNewSession, role: TLSRole, closing: TLSClosing, hostInfo: Option[(String, Int)]): TlsModule = {
|
def apply(attributes: Attributes, sslContext: SSLContext, sslConfig: Option[AkkaSSLConfig], firstSession: NegotiateNewSession, role: TLSRole, closing: TLSClosing, hostInfo: Option[(String, Int)]): TlsModule = {
|
||||||
val name = attributes.nameOrDefault(s"StreamTls($role)")
|
val name = attributes.nameOrDefault(s"StreamTls($role)")
|
||||||
val cipherIn = Inlet[ByteString](s"$name.cipherIn")
|
val cipherIn = Inlet[ByteString](s"$name.cipherIn")
|
||||||
val cipherOut = Outlet[ByteString](s"$name.cipherOut")
|
val cipherOut = Outlet[ByteString](s"$name.cipherOut")
|
||||||
val plainIn = Inlet[SslTlsOutbound](s"$name.transportIn")
|
val plainIn = Inlet[SslTlsOutbound](s"$name.transportIn")
|
||||||
val plainOut = Outlet[SslTlsInbound](s"$name.transportOut")
|
val plainOut = Outlet[SslTlsInbound](s"$name.transportOut")
|
||||||
val shape = new BidiShape(plainIn, cipherOut, cipherIn, plainOut)
|
val shape = new BidiShape(plainIn, cipherOut, cipherIn, plainOut)
|
||||||
TlsModule(plainIn, plainOut, cipherIn, cipherOut, shape, attributes, sslContext, firstSession, role, closing, hostInfo)
|
TlsModule(plainIn, plainOut, cipherIn, cipherOut, shape, attributes, sslContext, sslConfig, firstSession, role, closing, hostInfo)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ import akka.{ japi, NotUsed }
|
||||||
import akka.stream._
|
import akka.stream._
|
||||||
import akka.stream.TLSProtocol._
|
import akka.stream.TLSProtocol._
|
||||||
import akka.util.ByteString
|
import akka.util.ByteString
|
||||||
|
import com.typesafe.sslconfig.akka.AkkaSSLConfig
|
||||||
|
|
||||||
import scala.compat.java8.OptionConverters
|
import scala.compat.java8.OptionConverters
|
||||||
|
|
||||||
|
|
@ -48,6 +49,20 @@ import scala.compat.java8.OptionConverters
|
||||||
*/
|
*/
|
||||||
object TLS {
|
object TLS {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a StreamTls [[akka.stream.javadsl.BidiFlow]] in client mode. The
|
||||||
|
* SSLContext will be used to create an SSLEngine to which then the
|
||||||
|
* `firstSession` parameters are applied before initiating the first
|
||||||
|
* handshake. The `role` parameter determines the SSLEngine’s role; this is
|
||||||
|
* often the same as the underlying transport’s server or client role, but
|
||||||
|
* that is not a requirement and depends entirely on the application
|
||||||
|
* protocol.
|
||||||
|
*
|
||||||
|
* This method uses the default closing behavior or [[IgnoreComplete]].
|
||||||
|
*/
|
||||||
|
def create(sslContext: SSLContext, sslConfig: Optional[AkkaSSLConfig], firstSession: NegotiateNewSession, role: TLSRole): BidiFlow[SslTlsOutbound, ByteString, ByteString, SslTlsInbound, NotUsed] =
|
||||||
|
new javadsl.BidiFlow(scaladsl.TLS.apply(sslContext, OptionConverters.toScala(sslConfig), firstSession, role))
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a StreamTls [[akka.stream.javadsl.BidiFlow]] in client mode. The
|
* Create a StreamTls [[akka.stream.javadsl.BidiFlow]] in client mode. The
|
||||||
* SSLContext will be used to create an SSLEngine to which then the
|
* SSLContext will be used to create an SSLEngine to which then the
|
||||||
|
|
@ -60,7 +75,7 @@ object TLS {
|
||||||
* This method uses the default closing behavior or [[IgnoreComplete]].
|
* This method uses the default closing behavior or [[IgnoreComplete]].
|
||||||
*/
|
*/
|
||||||
def create(sslContext: SSLContext, firstSession: NegotiateNewSession, role: TLSRole): BidiFlow[SslTlsOutbound, ByteString, ByteString, SslTlsInbound, NotUsed] =
|
def create(sslContext: SSLContext, firstSession: NegotiateNewSession, role: TLSRole): BidiFlow[SslTlsOutbound, ByteString, ByteString, SslTlsInbound, NotUsed] =
|
||||||
new javadsl.BidiFlow(scaladsl.TLS.apply(sslContext, firstSession, role))
|
new javadsl.BidiFlow(scaladsl.TLS.apply(sslContext, None, firstSession, role))
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a StreamTls [[akka.stream.javadsl.BidiFlow]] in client mode. The
|
* Create a StreamTls [[akka.stream.javadsl.BidiFlow]] in client mode. The
|
||||||
|
|
@ -76,10 +91,29 @@ object TLS {
|
||||||
* The `hostInfo` parameter allows to optionally specify a pair of hostname and port
|
* The `hostInfo` parameter allows to optionally specify a pair of hostname and port
|
||||||
* that will be used when creating the SSLEngine with `sslContext.createSslEngine`.
|
* that will be used when creating the SSLEngine with `sslContext.createSslEngine`.
|
||||||
* The SSLEngine may use this information e.g. when an endpoint identification algorithm was
|
* The SSLEngine may use this information e.g. when an endpoint identification algorithm was
|
||||||
* configured using [[SSLParameters.setEndpointIdentificationAlgorithm]].
|
* configured using [[javax.net.ssl.SSLParameters.setEndpointIdentificationAlgorithm]].
|
||||||
|
*/
|
||||||
|
def create(sslContext: SSLContext, sslConfig: Optional[AkkaSSLConfig], firstSession: NegotiateNewSession, role: TLSRole, hostInfo: Optional[japi.Pair[String, java.lang.Integer]], closing: TLSClosing): BidiFlow[SslTlsOutbound, ByteString, ByteString, SslTlsInbound, NotUsed] =
|
||||||
|
new javadsl.BidiFlow(scaladsl.TLS.apply(sslContext, OptionConverters.toScala(sslConfig), firstSession, role, closing, OptionConverters.toScala(hostInfo).map(e ⇒ (e.first, e.second))))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a StreamTls [[akka.stream.javadsl.BidiFlow]] in client mode. The
|
||||||
|
* SSLContext will be used to create an SSLEngine to which then the
|
||||||
|
* `firstSession` parameters are applied before initiating the first
|
||||||
|
* handshake. The `role` parameter determines the SSLEngine’s role; this is
|
||||||
|
* often the same as the underlying transport’s server or client role, but
|
||||||
|
* that is not a requirement and depends entirely on the application
|
||||||
|
* protocol.
|
||||||
|
*
|
||||||
|
* For a description of the `closing` parameter please refer to [[TLSClosing]].
|
||||||
|
*
|
||||||
|
* The `hostInfo` parameter allows to optionally specify a pair of hostname and port
|
||||||
|
* that will be used when creating the SSLEngine with `sslContext.createSslEngine`.
|
||||||
|
* The SSLEngine may use this information e.g. when an endpoint identification algorithm was
|
||||||
|
* configured using [[javax.net.ssl.SSLParameters.setEndpointIdentificationAlgorithm]].
|
||||||
*/
|
*/
|
||||||
def create(sslContext: SSLContext, firstSession: NegotiateNewSession, role: TLSRole, hostInfo: Optional[japi.Pair[String, java.lang.Integer]], closing: TLSClosing): BidiFlow[SslTlsOutbound, ByteString, ByteString, SslTlsInbound, NotUsed] =
|
def create(sslContext: SSLContext, firstSession: NegotiateNewSession, role: TLSRole, hostInfo: Optional[japi.Pair[String, java.lang.Integer]], closing: TLSClosing): BidiFlow[SslTlsOutbound, ByteString, ByteString, SslTlsInbound, NotUsed] =
|
||||||
new javadsl.BidiFlow(scaladsl.TLS.apply(sslContext, firstSession, role, closing, OptionConverters.toScala(hostInfo).map(e ⇒ (e.first, e.second))))
|
new javadsl.BidiFlow(scaladsl.TLS.apply(sslContext, None, firstSession, role, closing, OptionConverters.toScala(hostInfo).map(e ⇒ (e.first, e.second))))
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ import akka.NotUsed
|
||||||
import akka.stream._
|
import akka.stream._
|
||||||
import akka.stream.TLSProtocol._
|
import akka.stream.TLSProtocol._
|
||||||
import akka.util.ByteString
|
import akka.util.ByteString
|
||||||
|
import com.typesafe.sslconfig.akka.AkkaSSLConfig
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stream cipher support based upon JSSE.
|
* Stream cipher support based upon JSSE.
|
||||||
|
|
@ -60,11 +61,54 @@ object TLS {
|
||||||
* The `hostInfo` parameter allows to optionally specify a pair of hostname and port
|
* The `hostInfo` parameter allows to optionally specify a pair of hostname and port
|
||||||
* that will be used when creating the SSLEngine with `sslContext.createSslEngine`.
|
* that will be used when creating the SSLEngine with `sslContext.createSslEngine`.
|
||||||
* The SSLEngine may use this information e.g. when an endpoint identification algorithm was
|
* The SSLEngine may use this information e.g. when an endpoint identification algorithm was
|
||||||
* configured using [[SSLParameters.setEndpointIdentificationAlgorithm]].
|
* configured using [[javax.net.ssl.SSLParameters.setEndpointIdentificationAlgorithm]].
|
||||||
*/
|
*/
|
||||||
def apply(sslContext: SSLContext, firstSession: NegotiateNewSession, role: TLSRole,
|
def apply(sslContext: SSLContext,
|
||||||
|
sslConfig: Option[AkkaSSLConfig],
|
||||||
|
firstSession: NegotiateNewSession, role: TLSRole,
|
||||||
closing: TLSClosing = IgnoreComplete, hostInfo: Option[(String, Int)] = None): scaladsl.BidiFlow[SslTlsOutbound, ByteString, ByteString, SslTlsInbound, NotUsed] =
|
closing: TLSClosing = IgnoreComplete, hostInfo: Option[(String, Int)] = None): scaladsl.BidiFlow[SslTlsOutbound, ByteString, ByteString, SslTlsInbound, NotUsed] =
|
||||||
new scaladsl.BidiFlow(TlsModule(Attributes.none, sslContext, firstSession, role, closing, hostInfo))
|
new scaladsl.BidiFlow(TlsModule(Attributes.none, sslContext, sslConfig, firstSession, role, closing, hostInfo))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a StreamTls [[akka.stream.scaladsl.BidiFlow]]. The
|
||||||
|
* SSLContext will be used to create an SSLEngine to which then the
|
||||||
|
* `firstSession` parameters are applied before initiating the first
|
||||||
|
* handshake. The `role` parameter determines the SSLEngine’s role; this is
|
||||||
|
* often the same as the underlying transport’s server or client role, but
|
||||||
|
* that is not a requirement and depends entirely on the application
|
||||||
|
* protocol.
|
||||||
|
*
|
||||||
|
* For a description of the `closing` parameter please refer to [[TLSClosing]].
|
||||||
|
*
|
||||||
|
* The `hostInfo` parameter allows to optionally specify a pair of hostname and port
|
||||||
|
* that will be used when creating the SSLEngine with `sslContext.createSslEngine`.
|
||||||
|
* The SSLEngine may use this information e.g. when an endpoint identification algorithm was
|
||||||
|
* configured using [[javax.net.ssl.SSLParameters.setEndpointIdentificationAlgorithm]].
|
||||||
|
*/
|
||||||
|
def apply(sslContext: SSLContext,
|
||||||
|
firstSession: NegotiateNewSession, role: TLSRole,
|
||||||
|
closing: TLSClosing, hostInfo: Option[(String, Int)]): scaladsl.BidiFlow[SslTlsOutbound, ByteString, ByteString, SslTlsInbound, NotUsed] =
|
||||||
|
new scaladsl.BidiFlow(TlsModule(Attributes.none, sslContext, None, firstSession, role, closing, hostInfo))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a StreamTls [[akka.stream.scaladsl.BidiFlow]]. The
|
||||||
|
* SSLContext will be used to create an SSLEngine to which then the
|
||||||
|
* `firstSession` parameters are applied before initiating the first
|
||||||
|
* handshake. The `role` parameter determines the SSLEngine’s role; this is
|
||||||
|
* often the same as the underlying transport’s server or client role, but
|
||||||
|
* that is not a requirement and depends entirely on the application
|
||||||
|
* protocol.
|
||||||
|
*
|
||||||
|
* For a description of the `closing` parameter please refer to [[TLSClosing]].
|
||||||
|
*
|
||||||
|
* The `hostInfo` parameter allows to optionally specify a pair of hostname and port
|
||||||
|
* that will be used when creating the SSLEngine with `sslContext.createSslEngine`.
|
||||||
|
* The SSLEngine may use this information e.g. when an endpoint identification algorithm was
|
||||||
|
* configured using [[javax.net.ssl.SSLParameters.setEndpointIdentificationAlgorithm]].
|
||||||
|
*/
|
||||||
|
def apply(sslContext: SSLContext,
|
||||||
|
firstSession: NegotiateNewSession, role: TLSRole): scaladsl.BidiFlow[SslTlsOutbound, ByteString, ByteString, SslTlsInbound, NotUsed] =
|
||||||
|
new scaladsl.BidiFlow(TlsModule(Attributes.none, sslContext, None, firstSession, role, IgnoreComplete, None))
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -850,6 +850,9 @@ object MiMa extends AutoPlugin {
|
||||||
// internal api
|
// internal api
|
||||||
FilterAnyProblemStartingWith("akka.stream.impl"),
|
FilterAnyProblemStartingWith("akka.stream.impl"),
|
||||||
|
|
||||||
|
// #20214 SNI disabling for single connections (AkkaSSLConfig being passed around)
|
||||||
|
ProblemFilters.exclude[ReversedMissingMethodProblem]("akka.http.javadsl.ConnectionContext.sslConfig"), // class meant only for internal extension
|
||||||
|
|
||||||
//#20229 migrate GroupBy to GraphStage
|
//#20229 migrate GroupBy to GraphStage
|
||||||
ProblemFilters.exclude[DirectMissingMethodProblem]("akka.stream.scaladsl.GraphDSL#Builder.deprecatedAndThen"),
|
ProblemFilters.exclude[DirectMissingMethodProblem]("akka.stream.scaladsl.GraphDSL#Builder.deprecatedAndThen"),
|
||||||
ProblemFilters.exclude[DirectMissingMethodProblem]("akka.stream.scaladsl.Flow.deprecatedAndThen"),
|
ProblemFilters.exclude[DirectMissingMethodProblem]("akka.stream.scaladsl.Flow.deprecatedAndThen"),
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue