Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: support mtls settings #2443

Merged
merged 1 commit into from
Dec 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 47 additions & 12 deletions zio-http/src/main/scala/zio/http/SSLConfig.scala
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,32 @@
package zio.http

import zio.Config
import zio.stacktracer.TracingImplicits.disableAutoTrace

import zio.http.SSLConfig._

final case class SSLConfig(behaviour: HttpBehaviour, data: Data, provider: Provider)
sealed trait ClientAuth

object ClientAuth {
case object Required extends ClientAuth
case object NoneClientAuth extends ClientAuth
case object Optional extends ClientAuth

}

final case class SSLConfig(
behaviour: HttpBehaviour,
data: Data,
provider: Provider,
clientAuth: Option[ClientAuth] = None,
)

object SSLConfig {

def apply(data: Data): SSLConfig =
new SSLConfig(HttpBehaviour.Redirect, data, Provider.JDK)
new SSLConfig(HttpBehaviour.Redirect, data, Provider.JDK, None)

def apply(data: Data, clientAuth: ClientAuth): SSLConfig =
new SSLConfig(HttpBehaviour.Redirect, data, Provider.JDK, Some(clientAuth))

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jdegoes @adamgfraser I tried to combine both the apply (and other duplicate functions below)
into single function like

def apply(data: Data, clientAuth: Option[ClientAuth] = None): SSLConfig =
    new SSLConfig(HttpBehaviour.Redirect, data, Provider.JDK, clientAuth)

But I'm getting below error -

/home/raj/Coding/scala/zio-http/zio-http/src/main/scala/zio/http/SSLConfig.scala:39:8: in object SSLConfig, multiple overloaded alternatives of method fromFile define default arguments.

I did workaround to make it compile. Not sure why the first option didn't work

val config: Config[SSLConfig] =
(
Expand All @@ -38,22 +54,41 @@ object SSLConfig {
}

def fromFile(certPath: String, keyPath: String): SSLConfig =
new SSLConfig(HttpBehaviour.Redirect, Data.FromFile(certPath, keyPath), Provider.JDK)
fromFile(HttpBehaviour.Redirect, certPath, keyPath)

def fromFile(certPath: String, keyPath: String, clientAuth: ClientAuth): SSLConfig =
fromFile(HttpBehaviour.Redirect, certPath, keyPath, Some(clientAuth))

def fromFile(behaviour: HttpBehaviour, certPath: String, keyPath: String): SSLConfig =
new SSLConfig(behaviour, Data.FromFile(certPath, keyPath), Provider.JDK)
def fromFile(
behaviour: HttpBehaviour,
certPath: String,
keyPath: String,
clientAuth: Option[ClientAuth] = None,
): SSLConfig =
new SSLConfig(behaviour, Data.FromFile(certPath, keyPath), Provider.JDK, clientAuth)

def fromResource(certPath: String, keyPath: String): SSLConfig =
new SSLConfig(HttpBehaviour.Redirect, Data.FromResource(certPath, keyPath), Provider.JDK)
fromResource(HttpBehaviour.Redirect, certPath, keyPath, None)

def fromResource(behaviour: HttpBehaviour, certPath: String, keyPath: String): SSLConfig =
new SSLConfig(behaviour, Data.FromResource(certPath, keyPath), Provider.JDK)
def fromResource(certPath: String, keyPath: String, clientAuth: ClientAuth): SSLConfig =
fromResource(HttpBehaviour.Redirect, certPath, keyPath, Some(clientAuth))

def fromResource(
behaviour: HttpBehaviour,
certPath: String,
keyPath: String,
clientAuth: Option[ClientAuth] = None,
): SSLConfig =
new SSLConfig(behaviour, Data.FromResource(certPath, keyPath), Provider.JDK, clientAuth)

def generate: SSLConfig =
new SSLConfig(HttpBehaviour.Redirect, Data.Generate, Provider.JDK)
generate(HttpBehaviour.Redirect, None)

def generate(clientAuth: ClientAuth): SSLConfig =
generate(HttpBehaviour.Redirect, Some(clientAuth))

def generate(behaviour: HttpBehaviour): SSLConfig =
new SSLConfig(behaviour, Data.Generate, Provider.JDK)
def generate(behaviour: HttpBehaviour, clientAuth: Option[ClientAuth] = None): SSLConfig =
new SSLConfig(behaviour, Data.Generate, Provider.JDK, clientAuth)

sealed trait HttpBehaviour
object HttpBehaviour {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,9 @@ package zio.http.netty.server
import java.io.FileInputStream
import java.util

import zio.stacktracer.TracingImplicits.disableAutoTrace

import zio.http.SSLConfig.{HttpBehaviour, Provider}
import zio.http.netty.Names
import zio.http.{SSLConfig, Server}
import zio.http.{ClientAuth, SSLConfig, Server}

import io.netty.buffer.ByteBuf
import io.netty.channel.ChannelHandlerContext
Expand All @@ -33,27 +31,38 @@ import io.netty.handler.ssl.ApplicationProtocolConfig.{
SelectedListenerFailureBehavior,
SelectorFailureBehavior,
}
import io.netty.handler.ssl._
import io.netty.handler.ssl.util.SelfSignedCertificate
import io.netty.handler.ssl.{SslContext, SslHandler, _}
import io.netty.handler.ssl.{ClientAuth => NettyClientAuth}
object SSLUtil {

def getClientAuth(clientAuth: ClientAuth): NettyClientAuth = clientAuth match {
case ClientAuth.Required => NettyClientAuth.REQUIRE
case ClientAuth.Optional => NettyClientAuth.OPTIONAL
case _ => NettyClientAuth.NONE
}

implicit class SslContextBuilderOps(self: SslContextBuilder) {
def toNettyProvider(sslProvider: Provider): SslProvider = sslProvider match {
case Provider.OpenSSL => SslProvider.OPENSSL
case Provider.JDK => SslProvider.JDK
}

def buildWithDefaultOptions(sslConfig: SSLConfig): SslContext = self
.sslProvider(toNettyProvider(sslConfig.provider))
.applicationProtocolConfig(
new ApplicationProtocolConfig(
Protocol.ALPN,
SelectorFailureBehavior.NO_ADVERTISE,
SelectedListenerFailureBehavior.ACCEPT,
ApplicationProtocolNames.HTTP_1_1,
),
)
.build()
def buildWithDefaultOptions(sslConfig: SSLConfig): SslContext = {
val clientAuthConfig: Option[ClientAuth] = sslConfig.clientAuth
clientAuthConfig.foreach(ca => self.clientAuth(getClientAuth(ca)))
self
.sslProvider(toNettyProvider(sslConfig.provider))
.applicationProtocolConfig(
new ApplicationProtocolConfig(
Protocol.ALPN,
SelectorFailureBehavior.NO_ADVERTISE,
SelectedListenerFailureBehavior.ACCEPT,
ApplicationProtocolNames.HTTP_1_1,
),
)
.build()
}
}

def sslConfigToSslContext(sslConfig: SSLConfig): SslContext = sslConfig.data match {
Expand Down
Loading