diff --git a/akka-docs/rst/java/code/docs/http/javadsl/HttpsExamplesDocTest.java b/akka-docs/rst/java/code/docs/http/javadsl/HttpsExamplesDocTest.java new file mode 100644 index 0000000000..8883594b1d --- /dev/null +++ b/akka-docs/rst/java/code/docs/http/javadsl/HttpsExamplesDocTest.java @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2009-2016 Lightbend Inc. + */ + +package docs.http.javadsl; + +import akka.actor.AbstractActor; +import akka.actor.ActorSystem; +import akka.http.javadsl.*; +import akka.http.javadsl.model.HttpRequest; +import akka.http.javadsl.model.HttpResponse; +import akka.japi.Pair; +import akka.japi.pf.ReceiveBuilder; +import akka.stream.ActorMaterializer; +import akka.stream.Materializer; +import akka.stream.javadsl.Flow; +import akka.stream.javadsl.Sink; +import akka.stream.javadsl.Source; +import com.typesafe.sslconfig.akka.AkkaSSLConfig; +import scala.concurrent.ExecutionContextExecutor; +import scala.util.Try; + +import java.util.concurrent.CompletionStage; + +import static akka.http.javadsl.ConnectHttp.toHost; +import static akka.pattern.PatternsCS.pipe; + +@SuppressWarnings("unused") +public class HttpsExamplesDocTest { + + // compile only test + public void testConstructRequest() { + String unsafeHost = "example.com"; + //#disable-sni-connection + final ActorSystem system = ActorSystem.create(); + final ActorMaterializer mat = ActorMaterializer.create(system); + final Http http = Http.get(system); + + // WARNING: disabling SNI is a very bad idea, please don't unless you have a very good reason to. + final AkkaSSLConfig defaultSSLConfig = AkkaSSLConfig.get(system); + final AkkaSSLConfig badSslConfig = defaultSSLConfig + .convertSettings(s -> s.withLoose(s.loose().withDisableSNI(true))); + final HttpsConnectionContext badCtx = http.createClientHttpsContext(badSslConfig); + + http.outgoingConnection(ConnectHttp.toHostHttps(unsafeHost).withCustomHttpsContext(badCtx)); + //#disable-sni-connection + } + +} diff --git a/akka-docs/rst/java/http/client-side/https-support.rst b/akka-docs/rst/java/http/client-side/https-support.rst index f9a9e02776..ad7082e760 100644 --- a/akka-docs/rst/java/http/client-side/https-support.rst +++ b/akka-docs/rst/java/http/client-side/https-support.rst @@ -45,8 +45,33 @@ to rely on the configured default client-side ``HttpsContext``. If no custom ``HttpsContext`` is defined the default context uses Java's default TLS settings. Customizing the ``HttpsContext`` can make the Https client less secure. Understand what you are doing! +Detailed configuration and workarounds +-------------------------------------- + +Akka HTTP relies on `Typesafe SSL-Config`_ which is a library maintained by Lightbend that makes configuring +things related to SSL/TLS much simpler than using the raw SSL APIs provided by the JDK. Please refer to its +documentation to learn more about it. + +All configuration options available to this library may be set under the ``akka.ssl-context`` configuration for Akka HTTP applications. + +.. note:: + When encountering problems connecting to HTTPS hosts we highly encourage to reading up on the excellent ssl-config + configuration. Especially the quick start sections about `adding certificates to the trust store`_ should prove + very useful, for example to easily trust a self-signed certificate that applications might use in development mode. + +.. warning:: + While it is possible to disable certain checks using the so called "loose" settings in SSL Config, we **strongly recommend** + to instead attempt to solve these issues by properly configuring TLS–for example by adding trusted keys to the keystore. + + If however certain checks really need to be disabled because of misconfigured (or legacy) servers that your + application has to speak to, instead of disabling the checks globally (i.e. in ``application.conf``) we suggest + configuring the loose settings for *specific connections* that are known to need them disabled (and trusted for some other reason). + The pattern of doing so is documented in the folowing sub-sections. + +.. _adding certificates to the trust store: http://typesafehub.github.io/ssl-config/WSQuickStart.html#connecting-to-a-remote-server-over-https + Hostname verification ---------------------- +^^^^^^^^^^^^^^^^^^^^^ Hostname verification proves that the Akka HTTP client is actually communicating with the server it intended to communicate with. Without this check a man-in-the-middle attack is possible. In the attack scenario, an alternative @@ -57,9 +82,43 @@ The default ``HttpsContext`` enables hostname verification. Akka HTTP relies on to implement this and security options for SSL/TLS. Hostname verification is provided by the JDK and used by Akka HTTP since Java 7, and on Java 6 the verification is implemented by ssl-config manually. -.. note:: - We highly recommend updating your Java runtime to the latest available release, - preferably JDK 8, as it includes this and many more security features related to TLS. +For further recommended reading we would like to highlight the `fixing hostname verification blog post`_ by blog post by Will Sargent. -.. _Typesafe SSL-Config: https://github.com/typesafehub/ssl-config +.. _Typesafe SSL-Config: http://typesafehub.github.io/ssl-config +.. _fixing hostname verification blog post: https://tersesystems.com/2014/03/23/fixing-hostname-verification/ .. _akka.http.javadsl.Http: @github@/akka-http-core/src/main/scala/akka/http/javadsl/Http.scala + + +Server Name Indication (SNI) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +SNI is an TLS extension which aims to guard against man-in-the-middle attacks. It does so by having the client send the +name of the virtual domain it is expecting to talk to as part of the TLS handshake. + +It is specified as part of `RFC 6066`_. + +Disabling TLS security features, at your own risk +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. warning:: + It is highly discouraged to disable any of the security features of TLS, however do acknowlage that workarounds may sometimes be needed. + + Before disabling any of the features one should consider if they may be solvable *within* the TLS world, + for example by `trusting a certificate`_, or `configuring the trusted cipher suites`_. + There's also a very important section in the ssl-config docs titled `LooseSSL - Please read this before turning anything off!`_. + + If disabling features is indeed desired, we recommend doing so for *specific connections*, + instead of globally configuring it via ``application.conf``. + +The following shows an example of disabling SNI for a given connection: + +.. includecode:: ../../code/docs/http/scaladsl/HttpsExamplesSpec.scala + :include: disable-sni-connection + +The ``badSslConfig`` is a copy of the default ``AkkaSSLConfig`` with with the slightly changed configuration to disable SNI. +This value can be cached and used for connections which should indeed not use this feature. + +.. _RFC 6066: https://tools.ietf.org/html/rfc6066#page-6 +.. _LooseSSL - Please read this before turning anything off!: http://typesafehub.github.io/ssl-config/LooseSSL.html#please-read-this-before-turning-anything-off +.. _trusting a certificate: http://typesafehub.github.io/ssl-config/WSQuickStart.html +.. _configuring the trusted cipher suites: http://typesafehub.github.io/ssl-config/CipherSuites.html diff --git a/akka-docs/rst/scala/code/docs/http/scaladsl/HttpsExamplesSpec.scala b/akka-docs/rst/scala/code/docs/http/scaladsl/HttpsExamplesSpec.scala new file mode 100644 index 0000000000..ff30a2479c --- /dev/null +++ b/akka-docs/rst/scala/code/docs/http/scaladsl/HttpsExamplesSpec.scala @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2009-2016 Lightbend Inc. + */ + +package docs.http.scaladsl + +import akka.actor.{ ActorLogging, ActorSystem } +import akka.http.scaladsl.Http +import akka.stream.ActorMaterializer +import akka.util.ByteString +import com.typesafe.sslconfig.akka.AkkaSSLConfig +import org.scalatest.{ Matchers, WordSpec } + +class HttpsExamplesSpec extends WordSpec with Matchers { + + "disable SNI for connection" in { + pending // compile-time only test + + val unsafeHost = "example.com" + //#disable-sni-connection + implicit val system = ActorSystem() + implicit val mat = ActorMaterializer() + + // WARNING: disabling SNI is a very bad idea, please don't unless you have a very good reason to. + val badSslConfig = AkkaSSLConfig().mapSettings(s => s.withLoose(s.loose.withDisableSNI(true))) + val badCtx = Http().createClientHttpsContext(badSslConfig) + Http().outgoingConnectionHttps(unsafeHost, connectionContext = badCtx) + //#disable-sni-connection + } +} \ No newline at end of file diff --git a/akka-docs/rst/scala/http/client-side/https-support.rst b/akka-docs/rst/scala/http/client-side/https-support.rst index 4c480db335..c3b421425b 100644 --- a/akka-docs/rst/scala/http/client-side/https-support.rst +++ b/akka-docs/rst/scala/http/client-side/https-support.rst @@ -45,8 +45,33 @@ to rely on the configured default client-side ``HttpsContext``. If no custom ``HttpsContext`` is defined the default context uses Java's default TLS settings. Customizing the ``HttpsContext`` can make the Https client less secure. Understand what you are doing! +Detailed configuration and workarounds +-------------------------------------- + +Akka HTTP relies on `Typesafe SSL-Config`_ which is a library maintained by Lightbend that makes configuring +things related to SSL/TLS much simpler than using the raw SSL APIs provided by the JDK. Please refer to its +documentation to learn more about it. + +All configuration options available to this library may be set under the ``akka.ssl-context`` configuration for Akka HTTP applications. + +.. note:: + When encountering problems connecting to HTTPS hosts we highly encourage to reading up on the excellent ssl-config + configuration. Especially the quick start sections about `adding certificates to the trust store`_ should prove + very useful, for example to easily trust a self-signed certificate that applications might use in development mode. + +.. warning:: + While it is possible to disable certain checks using the so called "loose" settings in SSL Config, we **strongly recommend** + to instead attempt to solve these issues by properly configuring TLS–for example by adding trusted keys to the keystore. + + If however certain checks really need to be disabled because of misconfigured (or legacy) servers that your + application has to speak to, instead of disabling the checks globally (i.e. in ``application.conf``) we suggest + configuring the loose settings for *specific connections* that are known to need them disabled (and trusted for some other reason). + The pattern of doing so is documented in the folowing sub-sections. + +.. _adding certificates to the trust store: http://typesafehub.github.io/ssl-config/WSQuickStart.html#connecting-to-a-remote-server-over-https + Hostname verification ---------------------- +^^^^^^^^^^^^^^^^^^^^^ Hostname verification proves that the Akka HTTP client is actually communicating with the server it intended to communicate with. Without this check a man-in-the-middle attack is possible. In the attack scenario, an alternative @@ -57,9 +82,40 @@ The default ``HttpsContext`` enables hostname verification. Akka HTTP relies on to implement this and security options for SSL/TLS. Hostname verification is provided by the JDK and used by Akka HTTP since Java 7, and on Java 6 the verification is implemented by ssl-config manually. -.. note:: - We highly recommend updating your Java runtime to the latest available release, - preferably JDK 8, as it includes this and many more security features related to TLS. +For further recommended reading we would like to highlight the `fixing hostname verification blog post`_ by blog post by Will Sargent. -.. _Typesafe SSL-Config: https://github.com/typesafehub/ssl-config +.. _Typesafe SSL-Config: http://typesafehub.github.io/ssl-config +.. _fixing hostname verification blog post: https://tersesystems.com/2014/03/23/fixing-hostname-verification/ .. _akka.http.scaladsl.Http: @github@/akka-http-core/src/main/scala/akka/http/scaladsl/Http.scala + +Server Name Indication (SNI) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +SNI is an TLS extension which aims to guard against man-in-the-middle attacks. It does so by having the client send the +name of the virtual domain it is expecting to talk to as part of the TLS handshake. + +It is specified as part of `RFC 6066`_. + +Disabling TLS security features, at your own risk +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. warning:: + It is highly discouraged to disable any of the security features of TLS, however do acknowlage that workarounds may sometimes be needed. + + Before disabling any of the features one should consider if they may be solvable *within* the TLS world, + for example by `trusting a certificate`_, or `configuring the trusted cipher suites`_ etc. + + If disabling features is indeed desired, we recommend doing so for *specific connections*, + instead of globally configuring it via ``application.conf``. + +The following shows an example of disabling SNI for a given connection: + +.. includecode:: ../../code/docs/http/scaladsl/HttpsExamplesSpec.scala + :include: disable-sni-connection + +The ``badSslConfig`` is a copy of the default ``AkkaSSLConfig`` with with the slightly changed configuration to disable SNI. +This value can be cached and used for connections which should indeed not use this feature. + +.. _RFC 6066: https://tools.ietf.org/html/rfc6066#page-6 +.. _trusting a certificate: http://typesafehub.github.io/ssl-config/WSQuickStart.html +.. _configuring the trusted cipher suites: http://typesafehub.github.io/ssl-config/CipherSuites.html \ No newline at end of file diff --git a/akka-http-core/src/main/scala/akka/http/javadsl/ConnectionContext.scala b/akka-http-core/src/main/scala/akka/http/javadsl/ConnectionContext.scala index 817b763050..8cc72354ec 100644 --- a/akka-http-core/src/main/scala/akka/http/javadsl/ConnectionContext.scala +++ b/akka-http-core/src/main/scala/akka/http/javadsl/ConnectionContext.scala @@ -12,6 +12,7 @@ import scala.compat.java8.OptionConverters object ConnectionContext { //#https-context-creation + // ConnectionContext /** Used to serve HTTPS traffic. */ def https(sslContext: SSLContext): HttpsConnectionContext = scaladsl.ConnectionContext.https(sslContext) diff --git a/akka-http-core/src/main/scala/akka/http/javadsl/Http.scala b/akka-http-core/src/main/scala/akka/http/javadsl/Http.scala index 985dcb45d6..e2ee99f9a1 100644 --- a/akka-http-core/src/main/scala/akka/http/javadsl/Http.scala +++ b/akka-http-core/src/main/scala/akka/http/javadsl/Http.scala @@ -12,6 +12,7 @@ import akka.http.javadsl.model.ws._ import akka.http.javadsl.settings.{ ConnectionPoolSettings, ClientConnectionSettings, ServerSettings } import akka.{ NotUsed, stream } import akka.stream.TLSProtocol._ +import com.typesafe.sslconfig.akka.AkkaSSLConfig import scala.concurrent.Future import scala.util.Try import akka.stream.scaladsl.Keep @@ -657,6 +658,12 @@ class Http(system: ExtendedActorSystem) extends akka.actor.Extension { def setDefaultClientHttpsContext(context: HttpsConnectionContext): Unit = delegate.setDefaultClientHttpsContext(context.asInstanceOf[akka.http.scaladsl.HttpsConnectionContext]) + def createClientHttpsContext(sslConfig: AkkaSSLConfig): HttpsConnectionContext = + delegate.createClientHttpsContext(sslConfig) + + def createDefaultClientHttpsContext(): HttpsConnectionContext = + delegate.createDefaultClientHttpsContext() + private def adaptTupleFlow[T, Mat](scalaFlow: stream.scaladsl.Flow[(scaladsl.model.HttpRequest, T), (Try[scaladsl.model.HttpResponse], T), Mat]): Flow[Pair[HttpRequest, T], Pair[Try[HttpResponse], T], Mat] = { implicit val _ = JavaMapping.identity[T] JavaMapping.toJava(scalaFlow)(JavaMapping.flowMapping[Pair[HttpRequest, T], (scaladsl.model.HttpRequest, T), Pair[Try[HttpResponse], T], (Try[scaladsl.model.HttpResponse], T), Mat]) diff --git a/akka-http-core/src/main/scala/akka/http/scaladsl/ConnectionContext.scala b/akka-http-core/src/main/scala/akka/http/scaladsl/ConnectionContext.scala index 4bfd7eca7a..888a88956b 100644 --- a/akka-http-core/src/main/scala/akka/http/scaladsl/ConnectionContext.scala +++ b/akka-http-core/src/main/scala/akka/http/scaladsl/ConnectionContext.scala @@ -20,6 +20,7 @@ trait ConnectionContext extends akka.http.javadsl.ConnectionContext { object ConnectionContext { //#https-context-creation + // ConnectionContext def https(sslContext: SSLContext, enabledCipherSuites: Option[immutable.Seq[String]] = None, enabledProtocols: Option[immutable.Seq[String]] = None, diff --git a/akka-http-core/src/main/scala/akka/http/scaladsl/Http.scala b/akka-http-core/src/main/scala/akka/http/scaladsl/Http.scala index a13e6b17cc..f3471e6879 100644 --- a/akka-http-core/src/main/scala/akka/http/scaladsl/Http.scala +++ b/akka-http-core/src/main/scala/akka/http/scaladsl/Http.scala @@ -42,6 +42,7 @@ class HttpExt(private val config: Config)(implicit val system: ActorSystem) exte import Http._ override val sslConfig = AkkaSSLConfig(system) + validateAndWarnAboutLooseSettings() private[this] val defaultConnectionPoolSettings = ConnectionPoolSettings(system) @@ -739,7 +740,31 @@ trait DefaultSSLContextCreation { protected def system: ActorSystem protected def sslConfig: AkkaSSLConfig - protected def createDefaultClientHttpsContext(): HttpsConnectionContext = { + // --- log warnings --- + private[this] def log = system.log + + def validateAndWarnAboutLooseSettings() = { + val WarningAboutGlobalLoose = "This is very dangerous and may expose you to man-in-the-middle attacks. " + + "If you are forced to interact with a server that is behaving such that you must disable this setting, " + + "please disable it for a given connection instead, by configuring a specific HttpsConnectionContext " + + "for use only for the trusted target that hostname verification would have blocked." + + if (sslConfig.config.loose.disableHostnameVerification) + log.warning("Detected that Hostname Verification is disabled globally (via ssl-config's akka.ssl-config.loose.disableHostnameVerification) for the Http extension! " + + WarningAboutGlobalLoose) + + if (sslConfig.config.loose.disableSNI) { + log.warning("Detected that Server Name Indication (SNI) is disabled globally (via ssl-config's akka.ssl-config.loose.disableSNI) for the Http extension! " + + WarningAboutGlobalLoose) + + } + } + // --- end of log warnings --- + + def createDefaultClientHttpsContext(): HttpsConnectionContext = + createClientHttpsContext(sslConfig) + + def createClientHttpsContext(sslConfig: AkkaSSLConfig): HttpsConnectionContext = { val config = sslConfig.config val log = Logging(system, getClass) @@ -776,8 +801,11 @@ trait DefaultSSLContextCreation { case SslClientAuth.Need ⇒ Some(TLSClientAuth.Need) case SslClientAuth.None ⇒ Some(TLSClientAuth.None) } + // hostname! - defaultParams.setEndpointIdentificationAlgorithm("https") + if (!sslConfig.config.loose.disableHostnameVerification) { + defaultParams.setEndpointIdentificationAlgorithm("https") + } new HttpsConnectionContext(sslContext, Some(cipherSuites.toList), Some(defaultProtocols.toList), clientAuth, Some(defaultParams)) } diff --git a/akka-http-core/src/test/scala/akka/http/scaladsl/SslConfigWarningsSpec.scala b/akka-http-core/src/test/scala/akka/http/scaladsl/SslConfigWarningsSpec.scala new file mode 100644 index 0000000000..d5fbc25395 --- /dev/null +++ b/akka-http-core/src/test/scala/akka/http/scaladsl/SslConfigWarningsSpec.scala @@ -0,0 +1,72 @@ +/** + * Copyright (C) 2016 Lightbend Inc. + */ + +package akka.http.scaladsl + +import akka.actor.ActorSystem +import akka.event.Logging +import akka.http.scaladsl.model.HttpMethods._ +import akka.http.scaladsl.model._ +import akka.stream.ActorMaterializer +import akka.testkit.{ EventFilter, TestKit, TestProbe } +import com.typesafe.config.{ Config, ConfigFactory } +import org.scalatest.{ Matchers, WordSpec } + +import scala.concurrent.Await +import scala.concurrent.duration._ + +class SslConfigWarningsSpec extends WordSpec with Matchers { + val testConf: Config = ConfigFactory.parseString(""" + akka.loglevel = INFO + akka.stdout-loglevel = INFO + akka.log-dead-letters = OFF + akka.http.server.request-timeout = infinite + + akka.ssl-config { + loose { + disableSNI = true + disableHostnameVerification = true + } + } + """) + + "ssl-config loose options should cause warnings to be logged" should { + + "warn if SNI is disabled globally" in { + implicit val system = ActorSystem(getClass.getSimpleName, testConf) + implicit val materializer = ActorMaterializer() + + val p = TestProbe() + system.eventStream.subscribe(p.ref, classOf[Logging.LogEvent]) + + EventFilter.warning(start = "Detected that Server Name Indication (SNI) is disabled globally ", occurrences = 1) intercept { + Http()(system) + } + + // the very big warning shall be logged only once per actor system (extension) + EventFilter.warning(start = "Detected that Server Name Indication (SNI) is disabled globally ", occurrences = 0) intercept { + Http()(system) + } + + TestKit.shutdownActorSystem(system) + } + + "warn if hostname verification is disabled globally" in { + implicit val system = ActorSystem(getClass.getSimpleName, testConf) + implicit val materializer = ActorMaterializer() + + val p = TestProbe() + system.eventStream.subscribe(p.ref, classOf[Logging.LogEvent]) + + val msgStart = "Detected that Hostname Verification is disabled globally " + + EventFilter.warning(start = msgStart, occurrences = 1) intercept { Http()(system) } + + // the very big warning shall be logged only once per actor system (extension) + EventFilter.warning(start = msgStart, occurrences = 0) intercept { Http()(system) } + + TestKit.shutdownActorSystem(system) + } + } +} diff --git a/akka-stream/src/main/scala/akka/stream/impl/io/TLSActor.scala b/akka-stream/src/main/scala/akka/stream/impl/io/TLSActor.scala index 403abf9ff6..72fa4d925e 100644 --- a/akka-stream/src/main/scala/akka/stream/impl/io/TLSActor.scala +++ b/akka-stream/src/main/scala/akka/stream/impl/io/TLSActor.scala @@ -157,30 +157,6 @@ private[akka] class TLSActor(settings: ActorMaterializerSettings, e } - // 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 - // resolves: https://github.com/akka/akka/issues/19287 - private def applySNI(hostname: String, params: SSLParameters): Unit = { - val serverName = new SNIHostName(hostname) - params.setServerNames(Collections.singletonList(serverName)) - } - - private def cloneSSLParameters(parameters: SSLParameters): SSLParameters = { - val clone = new SSLParameters() - - clone.setCipherSuites(parameters.getCipherSuites) - clone.setProtocols(parameters.getProtocols) - clone.setWantClientAuth(parameters.getWantClientAuth) - clone.setNeedClientAuth(parameters.getNeedClientAuth) - clone.setEndpointIdentificationAlgorithm(parameters.getEndpointIdentificationAlgorithm) - clone.setAlgorithmConstraints(parameters.getAlgorithmConstraints) - clone.setServerNames(parameters.getServerNames) - clone.setSNIMatchers(parameters.getSNIMatchers) - clone.setUseCipherSuitesOrder(parameters.getUseCipherSuitesOrder) - - clone - } - var currentSession = engine.getSession applySessionParameters(firstSession) @@ -193,12 +169,9 @@ private[akka] class TLSActor(settings: ActorMaterializerSettings, case Some(TLSClientAuth.Need) ⇒ engine.setNeedClientAuth(true) case _ ⇒ // do nothing } - params.sslParameters foreach { p ⇒ - //first copy the mutable SLLParameters before modifying to prevent race condition - val parameters = cloneSSLParameters(p) - hostInfo foreach { case (host, _) ⇒ applySNI(host, parameters) } - engine.setSSLParameters(parameters) - } + + // configure Server Name Indication unless ssl-config disabled it (in which case we already logged many warnings) + applySNI(params) engine.beginHandshake() lastHandshakeStatus = engine.getHandshakeStatus @@ -494,4 +467,31 @@ private[akka] class TLSActor(settings: ActorMaterializerSettings, if (tracing) log.debug(s"STOP Outbound Closed: ${engine.isOutboundDone} Inbound closed: ${engine.isInboundDone}") context.stop(self) } + + // Additional ssl-config related setup + + // 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 + // resolves: https://github.com/akka/akka/issues/19287 + private def applySNI(params: NegotiateNewSession): Unit = for { + sslParams ← params.sslParameters + (hostname, _) ← hostInfo + if !sslConfig.config.loose.disableSNI + } yield { + // first copy the *mutable* SLLParameters before modifying to prevent race condition in `setServerNames` + val clone = new SSLParameters() + clone.setCipherSuites(sslParams.getCipherSuites) + clone.setProtocols(sslParams.getProtocols) + clone.setWantClientAuth(sslParams.getWantClientAuth) + clone.setNeedClientAuth(sslParams.getNeedClientAuth) + clone.setEndpointIdentificationAlgorithm(sslParams.getEndpointIdentificationAlgorithm) + clone.setAlgorithmConstraints(sslParams.getAlgorithmConstraints) + clone.setSNIMatchers(sslParams.getSNIMatchers) + clone.setUseCipherSuitesOrder(sslParams.getUseCipherSuitesOrder) + + // apply the changes + clone.setServerNames(Collections.singletonList(new SNIHostName(hostname))) + engine.setSSLParameters(clone) + } + } diff --git a/project/Dependencies.scala b/project/Dependencies.scala index 6424fcd3c0..365c90ae24 100644 --- a/project/Dependencies.scala +++ b/project/Dependencies.scala @@ -53,7 +53,7 @@ object Dependencies { val reactiveStreams = "org.reactivestreams" % "reactive-streams" % "1.0.0" // CC0 // ssl-config - val sslConfigAkka = "com.typesafe" %% "ssl-config-akka" % "0.1.3" // ApacheV2 + val sslConfigAkka = "com.typesafe" %% "ssl-config-akka" % "0.2.1" // ApacheV2 // For akka-http spray-json support val sprayJson = "io.spray" %% "spray-json" % "1.3.2" // ApacheV2 diff --git a/project/MiMa.scala b/project/MiMa.scala index 1ddd05a8a3..ed915dd970 100644 --- a/project/MiMa.scala +++ b/project/MiMa.scala @@ -716,6 +716,10 @@ object MiMa extends AutoPlugin { // #19390 Add flow monitor ProblemFilters.exclude[ReversedMissingMethodProblem]("akka.stream.scaladsl.FlowOpsMat.monitor"), + // #20214 + ProblemFilters.exclude[ReversedMissingMethodProblem]("akka.http.scaladsl.DefaultSSLContextCreation.createClientHttpsContext"), + ProblemFilters.exclude[ReversedMissingMethodProblem]("akka.http.scaladsl.DefaultSSLContextCreation.validateAndWarnAboutLooseSettings"), + // #20080, #20081 remove race condition on HTTP client ProblemFilters.exclude[DirectMissingMethodProblem]("akka.http.scaladsl.Http#HostConnectionPool.gatewayFuture"), ProblemFilters.exclude[IncompatibleMethTypeProblem]("akka.http.scaladsl.Http#HostConnectionPool.copy"),