From e5f5545751cfbcdf58e7b06d032838711188e443 Mon Sep 17 00:00:00 2001 From: Francesco Serra Date: Thu, 28 Jul 2022 22:39:28 +0200 Subject: [PATCH 1/7] Create http4s mAuth middleware --- build.sbt | 18 +- .../mdsol/mauth/http4s/MAuthMiddleware.scala | 120 +++++++++ .../mauth/http4s/MAuthMiddlewareSuite.scala | 235 ++++++++++++++++++ project/Dependencies.scala | 12 + 4 files changed, 384 insertions(+), 1 deletion(-) create mode 100644 modules/mauth-authenticator-http4s/src/main/scala/com/mdsol/mauth/http4s/MAuthMiddleware.scala create mode 100644 modules/mauth-authenticator-http4s/src/test/scala/com/mdsol/mauth/http4s/MAuthMiddlewareSuite.scala diff --git a/build.sbt b/build.sbt index 16243007..09954f3c 100644 --- a/build.sbt +++ b/build.sbt @@ -144,6 +144,21 @@ lazy val `mauth-authenticator-akka-http` = scalaModuleProject("mauth-authenticat Dependencies.test(scalaTest, scalaMock, wiremock) ++ Dependencies.test(akkaHttpTestKit: _*).map(withExclusions) ) +lazy val `mauth-authenticator-http4s` = (project in file("modules/mauth-authenticator-http4s")) // don't need to cross-compile + .dependsOn(`mauth-authenticator-scala`,`mauth-test-utils` % "test") + .settings( + basicSettings, + moduleName := "mauth-authenticator-http4s", + publishSettings, + testFrameworks += new TestFramework("munit.Framework"), + libraryDependencies ++= + Dependencies.provided(http4s) ++ + Dependencies.compile(enumeratum) ++ + Dependencies.compile(log4cats) ++ + Dependencies.test(munitAndScalacheckForHttp4s: _*) + ) + + lazy val `mauth-jvm-clients` = (project in file(".")) .aggregate( `mauth-authenticator`, @@ -156,7 +171,8 @@ lazy val `mauth-jvm-clients` = (project in file(".")) `mauth-signer-sttp`, `mauth-signer-apachehttp`, `mauth-sender-sttp-akka-http`, - `mauth-test-utils` + `mauth-test-utils`, + `mauth-authenticator-http4s` ) .settings( basicSettings, diff --git a/modules/mauth-authenticator-http4s/src/main/scala/com/mdsol/mauth/http4s/MAuthMiddleware.scala b/modules/mauth-authenticator-http4s/src/main/scala/com/mdsol/mauth/http4s/MAuthMiddleware.scala new file mode 100644 index 00000000..20e77e1d --- /dev/null +++ b/modules/mauth-authenticator-http4s/src/main/scala/com/mdsol/mauth/http4s/MAuthMiddleware.scala @@ -0,0 +1,120 @@ +package com.mdsol.mauth.http4s + +import cats.arrow.FunctionK +import cats.data.{Kleisli, OptionT} +import cats.effect.Sync +import cats.syntax.all._ +import cats.effect.kernel.Async +import cats.{Monad, MonadThrow, ~>} +import com.mdsol.mauth.MAuthRequest +import com.mdsol.mauth.scaladsl.Authenticator +import org.http4s.{Http, HttpApp, HttpRoutes, Response, Status} +import org.http4s.EntityDecoder._ +import org.typelevel.ci.CIString +import enumeratum._ +import org.typelevel.ci._ +import org.typelevel.log4cats.slf4j.Slf4jLogger + +import scala.concurrent.ExecutionContext +import scala.concurrent.duration.Duration +import scala.util.Try + +final case class MdsolAuthMissingHeaderRejection(headerName: String) extends Throwable + +sealed trait HeaderVersion extends EnumEntry + +object HeaderVersion extends Enum[HeaderVersion] { + val values = findValues + + case object V1 extends HeaderVersion { + val authHeaderName = ci"${MAuthRequest.X_MWS_AUTHENTICATION_HEADER_NAME}" + val timeHeaderName = ci"${MAuthRequest.X_MWS_TIME_HEADER_NAME}" + } + case object V2 extends HeaderVersion { + val authHeaderName = ci"${MAuthRequest.MCC_AUTHENTICATION_HEADER_NAME}" + val timeHeaderName = ci"${MAuthRequest.MCC_TIME_HEADER_NAME}" + } +} + +object MAuthMiddleware { + import HeaderVersion._ + def apply[G[_]: Sync,F[_]](requestValidationTimeout: Duration, fk: F ~> G)(http: Http[G,F])( + implicit authenticator: Authenticator, + ec: ExecutionContext, + F: Async[F] + ): Http[G,F] = + Kleisli { request => + val logger = Slf4jLogger.getLogger[G] + + def logAndReturnDefaultUnauthorizedReq(errorLogMsg: String) = + logger.warn(errorLogMsg) *> + Response[F](status = Status.Unauthorized).pure[G] + + def extractHeader[A](headerName: CIString)(f: String => F[A]) = + request.headers.get(headerName).map(_.head) + .fold(F.raiseError[A](MdsolAuthMissingHeaderRejection(headerName.toString))) { header => + f(header.value) + } + + def extractAll(headerVersion:HeaderVersion) = { + val (ahn,thn) = headerVersion match { + case V1 => (V1.authHeaderName,V1.timeHeaderName) + case V2 => (V2.authHeaderName,V2.timeHeaderName) + } + for { + authHeadValue <- extractHeader(ahn)(s => s.pure[F]) + timeHeadValue <- extractHeader(thn)(s => Try(s.toLong).liftTo[F]) + } yield (authHeadValue,timeHeadValue) + + } + + def getHeaderValOrEmpty(headerName: CIString) = + request.headers.get(headerName).map(_.head).fold("")(h => h.value) + + val authHeaderTimeHeader = + if (authenticator.isV2OnlyAuthenticate) + extractAll(V2) + else + extractAll(V2) orElse extractAll(V1) + + fk(request.as[Array[Byte]].flatMap { byteArray => + + authHeaderTimeHeader.flatMap { case (authHeader,timeHeader) => + val mAuthRequest: MAuthRequest = new MAuthRequest( + authHeader, + byteArray, + request.method.name, + timeHeader.toString, + request.uri.path.renderString, + request.uri.query.renderString + ) + + // this mimics MAuthDirectives in the akka package - really needed? + val req = if (!authenticator.isV2OnlyAuthenticate) { + mAuthRequest.setXmwsSignature(getHeaderValOrEmpty(V1.authHeaderName)) // dreadful mutating type + mAuthRequest.setXmwsTime(getHeaderValOrEmpty(V1.timeHeaderName)) + mAuthRequest + } else mAuthRequest + + F.fromFuture(F.delay(authenticator.authenticate(req)(ec,requestValidationTimeout))) + } + }).flatMap(b => + if (b) http(request) + else logAndReturnDefaultUnauthorizedReq(s"Rejecting request as authentication failed") + ).recoverWith { + case MdsolAuthMissingHeaderRejection(hn) => + logAndReturnDefaultUnauthorizedReq(s"Rejecting request as header ${hn} missing") + } + } + + def httpRoutes[F[_]: Async](requestValidationTimeout: Duration)(httpRoutes: HttpRoutes[F])( + implicit authenticator: Authenticator, + ec: ExecutionContext + ): HttpRoutes[F] = apply(requestValidationTimeout, OptionT.liftK[F])(httpRoutes) + + + def httpApp[F[_]: Async](requestValidationTimeout: Duration)(httpRoutes: HttpApp[F])( + implicit authenticator: Authenticator, + ec: ExecutionContext + ): HttpApp[F] = apply(requestValidationTimeout, FunctionK.id[F])(httpRoutes) +} diff --git a/modules/mauth-authenticator-http4s/src/test/scala/com/mdsol/mauth/http4s/MAuthMiddlewareSuite.scala b/modules/mauth-authenticator-http4s/src/test/scala/com/mdsol/mauth/http4s/MAuthMiddlewareSuite.scala new file mode 100644 index 00000000..f7b3eb24 --- /dev/null +++ b/modules/mauth-authenticator-http4s/src/test/scala/com/mdsol/mauth/http4s/MAuthMiddlewareSuite.scala @@ -0,0 +1,235 @@ +package com.mdsol.mauth.http4s + +import cats.effect._ +import cats.syntax.all._ +import com.mdsol.mauth.MAuthRequest +import com.mdsol.mauth.exception.MAuthValidationException +import com.mdsol.mauth.scaladsl.RequestAuthenticator +import com.mdsol.mauth.scaladsl.utils.ClientPublicKeyProvider +import com.mdsol.mauth.test.utils.TestFixtures +import com.mdsol.mauth.util.{EpochTimeProvider, MAuthKeysHelper} +import munit.CatsEffectSuite +import org.bouncycastle.jce.provider.BouncyCastleProvider +import org.http4s._ +import org.http4s.{HttpRoutes, Request, Response} +import org.http4s.syntax.literals._ +import org.http4s.Method._ + +import java.security.{PublicKey, Security} +import java.util.UUID +import scala.concurrent.{ExecutionContext, Future} +import scala.concurrent.duration._ + +class MAuthMiddlewareSuite extends CatsEffectSuite { + + private val route: HttpRoutes[IO] = + HttpRoutes.of { + case req if req.uri.path === path"/" => + Response[IO](Status.Ok).withEntity("pong").pure[IO] + } + + Security.addProvider(new BouncyCastleProvider) + + private val appUuid: UUID = UUID.fromString("2a6790ab-f6c6-45be-86fc-9e9be76ec12a") + private val authPrefix: String = "MWS" + private val authPrefixV2: String = "MWSV2" + + private val signature: String = "ih3xq6OvQ2/D5ktPDaZ4F6tanzdn2XGzZ+KOaFXC+YKVjNcSCfUiKB6T/552K3AmKm/" + + "yZF4rdEOpsMZ0QkuFqEZdwQ8R3iWUwdrNPsmNXSVvF50pRAlcI77UP5" + + "gUKV01xjZxfZ/M/vhzVn513bAgJ6CM8X4dtG20ki5xLsO35e2eZs5i9IwA/hEaKSm/" + + "PH2pEHwxz5c9MMGtHiFgzgXGacziVn0fr2c6X5jb3cDjHnfNVX8o57kFjL5E0YOoeEK" + + "DwHyflGhbfFNZys29jo83JCK2MQj9s+fZq5NsgmwuACRE6BnqKSPqwDWN4OK3N/iPcTwCsMKz/c5/3CEbMTlH8A==" + val signatureV2: String = + s"""h0MJYf5/zlX9VqqchANLr7XUln0RydMV4msZSXzLq2sbr3X+TGeJ60K9ZSlSuRrzyHbzzwuZABA + |3P2j3l9t+gyBC1c/JSa8mldMrIXXYzp0lYLxLkghH09hm3k0pEW2la94K/Num3xgNymn6D/B9dJ1onRIgl+T+e/m4k6 + |T3apKHcV/6cJ9asm+jDjzB8OuCVWVsLZQKQbtiydUYNisYerKVxWPLs9SHNZ6GmAqq4ZCCpyEQZuMNF6cMmXgQ0Pxe9 + |X/yNA1Xc3Fakuga47lUQ6Bn7xvhkH6P+ZP0k4U7kidziXpxpkDts8fEXTpkvFX0PR7vaxjbMZzWsU413jyNsw==;""".stripMargin.replaceAll("\n", "") + + val wrongSignatureV2: String = + """et2ht0OkDx20yWlPvOQn1jdTFaT3rS//3t+yl0VqiTgqeMae7x24/UzfD2WQ + |Bk6o226eQVnCloRjGgq9iLqIIf1wrAFy4CjEHPVCwKOcfbpVQBJYLCyL3Ilz + |VX6oDmV1Ghukk29mIlgmHGhfHPwGf3vMPvgCQ42GsnAKpRrQ9T4L2IWMM9gk + |WRAFYDXE3igTM+mWBz3IRrJMLnC2440N/KFNmwh3mVCDxIx/3D4xGhhiGZwA + |udVbIHmOG045CTSlajxWSNCbClM3nBmAzZn+wRD3DvdvHvDMiAtfVpz7rNLq + |2rBY2KRNJmPBaAV5ss30FC146jfyg7b8I9fenyauaw==;""".stripMargin.replaceAll("\n", "") + val wrongAuthHeaderV2: String = s"$authPrefixV2 $appUuid:$wrongSignatureV2" + + private val authHeader: String = s"$authPrefix $appUuid:$signature" + private val authHeaderV2: String = s"$authPrefixV2 $appUuid:$signatureV2" + + private val requestValidationTimeout: Duration = 10.seconds + + private val timeHeader: Long = 1509041057L + private val publicKey = MAuthKeysHelper.getPublicKeyFromString(TestFixtures.PUBLIC_KEY_1) + + private val client = new ClientPublicKeyProvider { + override def getPublicKey(appUUID: UUID): Future[Option[PublicKey]] = + if (appUUID == appUuid) { + Future(publicKey.some) + } + else Future.failed(new Throwable("Wrong app UUID")) + override def getPublicKeyIO(appUUID: UUID): IO[Option[PublicKey]] = ??? + } + + private val epochTimeProvider = new EpochTimeProvider { + override def inSeconds(): Long = timeHeader + } + + private implicit val authenticator: RequestAuthenticator = new RequestAuthenticator(client, epochTimeProvider) + + private val service = MAuthMiddleware.httpRoutes[IO](requestValidationTimeout)(route).orNotFound + + val authenticatorV2: RequestAuthenticator = new RequestAuthenticator(client, epochTimeProvider, v2OnlyAuthenticate = true) + val serviceV2 = MAuthMiddleware.httpRoutes[IO](requestValidationTimeout)(route)(implicitly[Async[IO]], authenticatorV2,implicitly[ExecutionContext]).orNotFound + + + test("allow successfully authenticated request") { + val res = service(Request[IO](GET,uri"/").withHeaders( + MAuthRequest.X_MWS_TIME_HEADER_NAME -> timeHeader.toString, + MAuthRequest.X_MWS_AUTHENTICATION_HEADER_NAME -> authHeader + )) + + res.map(_.status).assertEquals(Status.Ok) + } + + test("allow successfully authenticated request with both v1 and v2 headers, with V2 headers taking precedence") { + val res = service(Request[IO](GET,uri"/").withHeaders( + MAuthRequest.MCC_TIME_HEADER_NAME -> timeHeader.toString, + MAuthRequest.MCC_AUTHENTICATION_HEADER_NAME -> authHeaderV2, + MAuthRequest.X_MWS_TIME_HEADER_NAME -> (timeHeader - requestValidationTimeout.toSeconds - 10).toString, + MAuthRequest.X_MWS_AUTHENTICATION_HEADER_NAME -> "invalid auth header" + )) + + res.map(_.status).assertEquals(Status.Ok) + } + + test("allow successfully authenticated request with both v1 and v2 headers, fallback to v1 if v2 failed") { + val res = service(Request[IO](GET,uri"/").withHeaders( + MAuthRequest.MCC_TIME_HEADER_NAME -> timeHeader.toString, + MAuthRequest.MCC_AUTHENTICATION_HEADER_NAME -> wrongAuthHeaderV2, + MAuthRequest.X_MWS_TIME_HEADER_NAME -> timeHeader.toString, + MAuthRequest.X_MWS_AUTHENTICATION_HEADER_NAME -> authHeader + )) + + res.map(_.status).assertEquals(Status.Ok) + } + + test("reject request if validation times out") { + val res = service(Request[IO](GET,uri"/").withHeaders( + MAuthRequest.X_MWS_TIME_HEADER_NAME -> (timeHeader - requestValidationTimeout.toSeconds - 10).toString, + MAuthRequest.X_MWS_AUTHENTICATION_HEADER_NAME -> authHeader + )) + + res.redeem({ + case e if e.isInstanceOf[MAuthValidationException] => true // TODO: fix removing the throwing of random Exceptions + case _ => false // any other exception shouldn't be thrown + }, + _ => false + ).assert + } + + test("reject if public key cannot be found") { + val localClient = new ClientPublicKeyProvider { + override def getPublicKey(appUUID: UUID): Future[Option[PublicKey]] = + if (appUUID == appUuid) { + Future(none) + } + else Future.failed(new Throwable("Wrong app UUID")) + override def getPublicKeyIO(appUUID: UUID): IO[Option[PublicKey]] = ??? + } + + val localAuthenticator: RequestAuthenticator = new RequestAuthenticator(localClient, epochTimeProvider) + val localService = MAuthMiddleware.httpRoutes[IO](requestValidationTimeout)(route)(implicitly[Async[IO]], localAuthenticator,implicitly[ExecutionContext]).orNotFound + + val res = localService(Request[IO](GET,uri"/").withHeaders( + MAuthRequest.X_MWS_TIME_HEADER_NAME -> timeHeader.toString, + MAuthRequest.X_MWS_AUTHENTICATION_HEADER_NAME -> authHeader + )) + + res.map(_.status).assertEquals(Status.Unauthorized) + } + + test("reject if Authentication header is missing") { + val res = service(Request[IO](GET,uri"/").withHeaders( + MAuthRequest.X_MWS_TIME_HEADER_NAME -> timeHeader.toString + )) + + res.map(_.status).assertEquals(Status.Unauthorized) + } + + test("reject if Time header is missing") { + val res = service(Request[IO](GET,uri"/").withHeaders( + MAuthRequest.X_MWS_TIME_HEADER_NAME -> timeHeader.toString + )) + + res.map(_.status).assertEquals(Status.Unauthorized) + } + + test("allow successfully authenticated request when authenticator supports v2 only with both v1 and v2 headers, with V2 headers taking precedence") { + val res = serviceV2(Request[IO](GET,uri"/").withHeaders( + MAuthRequest.MCC_TIME_HEADER_NAME -> timeHeader.toString, + MAuthRequest.MCC_AUTHENTICATION_HEADER_NAME -> authHeaderV2, + MAuthRequest.X_MWS_TIME_HEADER_NAME -> (timeHeader - requestValidationTimeout.toSeconds - 10).toString, + MAuthRequest.X_MWS_AUTHENTICATION_HEADER_NAME -> "invalid auth header" + )) + + res.map(_.status).assertEquals(Status.Ok) + } + + test("allow successfully authenticated request with V2 headers") { + val res = serviceV2(Request[IO](GET,uri"/").withHeaders( + MAuthRequest.MCC_TIME_HEADER_NAME -> timeHeader.toString, + MAuthRequest.MCC_AUTHENTICATION_HEADER_NAME -> authHeaderV2 + )) + + res.map(_.status).assertEquals(Status.Ok) + } + + test("allow successfully authenticated request with V2 headers uppercase'd") { + val res = serviceV2(Request[IO](GET,uri"/").withHeaders( + MAuthRequest.MCC_TIME_HEADER_NAME -> timeHeader.toString, + MAuthRequest.MCC_AUTHENTICATION_HEADER_NAME.toUpperCase -> authHeaderV2 + )) + + res.map(_.status).assertEquals(Status.Ok) + } + + test("reject v2 request if it times out") { + val res = serviceV2(Request[IO](GET,uri"/").withHeaders( + MAuthRequest.MCC_TIME_HEADER_NAME -> (timeHeader - requestValidationTimeout.toSeconds - 10).toString, + MAuthRequest.MCC_AUTHENTICATION_HEADER_NAME -> authHeaderV2 + )) + + res.redeem({ + case e if e.isInstanceOf[MAuthValidationException] => true // TODO: fix removing the throwing of random Exceptions + case _ => false // any other exception shouldn't be thrown + }, + _ => false + ).assert + } + + test("reject v2 request if Authentication header is missing") { + val res = serviceV2(Request[IO](GET,uri"/").withHeaders( + MAuthRequest.MCC_TIME_HEADER_NAME -> timeHeader.toString + )) + + res.map(_.status).assertEquals(Status.Unauthorized) + } + + test("reject v2 request if Time header is missing") { + val res = serviceV2(Request[IO](GET,uri"/").withHeaders( + MAuthRequest.MCC_AUTHENTICATION_HEADER_NAME -> authHeaderV2 + )) + + res.map(_.status).assertEquals(Status.Unauthorized) + } + + test("reject if only v1 headers provided when authenticator is v2 only") { + val res = serviceV2(Request[IO](GET,uri"/").withHeaders( + MAuthRequest.X_MWS_TIME_HEADER_NAME -> timeHeader.toString, + MAuthRequest.X_MWS_AUTHENTICATION_HEADER_NAME -> authHeader + )) + + res.map(_.status).assertEquals(Status.Unauthorized) + } +} diff --git a/project/Dependencies.scala b/project/Dependencies.scala index aa6a0625..c6b580d8 100644 --- a/project/Dependencies.scala +++ b/project/Dependencies.scala @@ -7,6 +7,9 @@ object Dependencies extends DependencyUtils { val akkaHttp = "10.2.4" val logback = "1.2.3" val sttp = "3.2.0" + val http4s = "0.23.14" + val enumeratum = "1.7.0" + val log4cats = "2.1.1" } val akkaHttp: ModuleID = "com.typesafe.akka" %% "akka-http" % Version.akkaHttp @@ -28,6 +31,9 @@ object Dependencies extends DependencyUtils { val sttpAkkaHttpBackend: ModuleID = "com.softwaremill.sttp.client3" %% "akka-http-backend" % Version.sttp val scalaLibCompat: ModuleID = "org.scala-lang.modules" %% "scala-collection-compat" % "2.4.3" val caffeine: ModuleID = "com.github.ben-manes.caffeine" % "caffeine" % "2.9.1" + val http4s: ModuleID = "org.http4s" %% "http4s-dsl" % Version.http4s + val enumeratum: ModuleID = "com.beachape" %% "enumeratum" % Version.enumeratum + val log4cats = "org.typelevel" %% "log4cats-slf4j" % Version.log4cats // TEST DEPENDENCIES val akkaHttpTestKit: Seq[ModuleID] = Seq( @@ -40,6 +46,12 @@ object Dependencies extends DependencyUtils { val scalaTest: ModuleID = "org.scalatest" %% "scalatest" % "3.2.7" val wiremock: ModuleID = "com.github.tomakehurst" % "wiremock" % "2.27.2" + val munitAndScalacheckForHttp4s: Seq[ModuleID] = Seq( + "org.typelevel" %% "discipline-munit" % "1.0.9", + "org.typelevel" %% "munit-cats-effect-3" % "1.0.7", + "org.typelevel" %% "scalacheck-effect-munit" % "1.0.4" + ) + // Dependency Conflict Resolution val exclusions = Seq() val mccLibDependencyOverrides = Set() From 0e32c365e388d6e3a9664c70c20e1eed92fd322e Mon Sep 17 00:00:00 2001 From: Francesco Serra Date: Fri, 29 Jul 2022 12:36:37 +0200 Subject: [PATCH 2/7] scalafmt --- .../mdsol/mauth/http4s/MAuthMiddleware.scala | 49 +++-- .../mauth/http4s/MAuthMiddlewareSuite.scala | 191 ++++++++++-------- 2 files changed, 136 insertions(+), 104 deletions(-) diff --git a/modules/mauth-authenticator-http4s/src/main/scala/com/mdsol/mauth/http4s/MAuthMiddleware.scala b/modules/mauth-authenticator-http4s/src/main/scala/com/mdsol/mauth/http4s/MAuthMiddleware.scala index 20e77e1d..5b1c1cdb 100644 --- a/modules/mauth-authenticator-http4s/src/main/scala/com/mdsol/mauth/http4s/MAuthMiddleware.scala +++ b/modules/mauth-authenticator-http4s/src/main/scala/com/mdsol/mauth/http4s/MAuthMiddleware.scala @@ -5,7 +5,7 @@ import cats.data.{Kleisli, OptionT} import cats.effect.Sync import cats.syntax.all._ import cats.effect.kernel.Async -import cats.{Monad, MonadThrow, ~>} +import cats.{~>, Monad, MonadThrow} import com.mdsol.mauth.MAuthRequest import com.mdsol.mauth.scaladsl.Authenticator import org.http4s.{Http, HttpApp, HttpRoutes, Response, Status} @@ -38,11 +38,11 @@ object HeaderVersion extends Enum[HeaderVersion] { object MAuthMiddleware { import HeaderVersion._ - def apply[G[_]: Sync,F[_]](requestValidationTimeout: Duration, fk: F ~> G)(http: Http[G,F])( - implicit authenticator: Authenticator, + def apply[G[_]: Sync, F[_]](requestValidationTimeout: Duration, fk: F ~> G)(http: Http[G, F])(implicit + authenticator: Authenticator, ec: ExecutionContext, F: Async[F] - ): Http[G,F] = + ): Http[G, F] = Kleisli { request => val logger = Slf4jLogger.getLogger[G] @@ -51,20 +51,22 @@ object MAuthMiddleware { Response[F](status = Status.Unauthorized).pure[G] def extractHeader[A](headerName: CIString)(f: String => F[A]) = - request.headers.get(headerName).map(_.head) - .fold(F.raiseError[A](MdsolAuthMissingHeaderRejection(headerName.toString))) { header => - f(header.value) - } - - def extractAll(headerVersion:HeaderVersion) = { - val (ahn,thn) = headerVersion match { - case V1 => (V1.authHeaderName,V1.timeHeaderName) - case V2 => (V2.authHeaderName,V2.timeHeaderName) + request.headers + .get(headerName) + .map(_.head) + .fold(F.raiseError[A](MdsolAuthMissingHeaderRejection(headerName.toString))) { header => + f(header.value) + } + + def extractAll(headerVersion: HeaderVersion) = { + val (ahn, thn) = headerVersion match { + case V1 => (V1.authHeaderName, V1.timeHeaderName) + case V2 => (V2.authHeaderName, V2.timeHeaderName) } for { authHeadValue <- extractHeader(ahn)(s => s.pure[F]) timeHeadValue <- extractHeader(thn)(s => Try(s.toLong).liftTo[F]) - } yield (authHeadValue,timeHeadValue) + } yield (authHeadValue, timeHeadValue) } @@ -78,8 +80,7 @@ object MAuthMiddleware { extractAll(V2) orElse extractAll(V1) fk(request.as[Array[Byte]].flatMap { byteArray => - - authHeaderTimeHeader.flatMap { case (authHeader,timeHeader) => + authHeaderTimeHeader.flatMap { case (authHeader, timeHeader) => val mAuthRequest: MAuthRequest = new MAuthRequest( authHeader, byteArray, @@ -96,25 +97,23 @@ object MAuthMiddleware { mAuthRequest } else mAuthRequest - F.fromFuture(F.delay(authenticator.authenticate(req)(ec,requestValidationTimeout))) + F.fromFuture(F.delay(authenticator.authenticate(req)(ec, requestValidationTimeout))) } }).flatMap(b => if (b) http(request) else logAndReturnDefaultUnauthorizedReq(s"Rejecting request as authentication failed") - ).recoverWith { - case MdsolAuthMissingHeaderRejection(hn) => - logAndReturnDefaultUnauthorizedReq(s"Rejecting request as header ${hn} missing") + ).recoverWith { case MdsolAuthMissingHeaderRejection(hn) => + logAndReturnDefaultUnauthorizedReq(s"Rejecting request as header $hn missing") } } - def httpRoutes[F[_]: Async](requestValidationTimeout: Duration)(httpRoutes: HttpRoutes[F])( - implicit authenticator: Authenticator, + def httpRoutes[F[_]: Async](requestValidationTimeout: Duration)(httpRoutes: HttpRoutes[F])(implicit + authenticator: Authenticator, ec: ExecutionContext ): HttpRoutes[F] = apply(requestValidationTimeout, OptionT.liftK[F])(httpRoutes) - - def httpApp[F[_]: Async](requestValidationTimeout: Duration)(httpRoutes: HttpApp[F])( - implicit authenticator: Authenticator, + def httpApp[F[_]: Async](requestValidationTimeout: Duration)(httpRoutes: HttpApp[F])(implicit + authenticator: Authenticator, ec: ExecutionContext ): HttpApp[F] = apply(requestValidationTimeout, FunctionK.id[F])(httpRoutes) } diff --git a/modules/mauth-authenticator-http4s/src/test/scala/com/mdsol/mauth/http4s/MAuthMiddlewareSuite.scala b/modules/mauth-authenticator-http4s/src/test/scala/com/mdsol/mauth/http4s/MAuthMiddlewareSuite.scala index f7b3eb24..36a19f08 100644 --- a/modules/mauth-authenticator-http4s/src/test/scala/com/mdsol/mauth/http4s/MAuthMiddlewareSuite.scala +++ b/modules/mauth-authenticator-http4s/src/test/scala/com/mdsol/mauth/http4s/MAuthMiddlewareSuite.scala @@ -66,8 +66,7 @@ class MAuthMiddlewareSuite extends CatsEffectSuite { override def getPublicKey(appUUID: UUID): Future[Option[PublicKey]] = if (appUUID == appUuid) { Future(publicKey.some) - } - else Future.failed(new Throwable("Wrong app UUID")) + } else Future.failed(new Throwable("Wrong app UUID")) override def getPublicKeyIO(appUUID: UUID): IO[Option[PublicKey]] = ??? } @@ -80,52 +79,63 @@ class MAuthMiddlewareSuite extends CatsEffectSuite { private val service = MAuthMiddleware.httpRoutes[IO](requestValidationTimeout)(route).orNotFound val authenticatorV2: RequestAuthenticator = new RequestAuthenticator(client, epochTimeProvider, v2OnlyAuthenticate = true) - val serviceV2 = MAuthMiddleware.httpRoutes[IO](requestValidationTimeout)(route)(implicitly[Async[IO]], authenticatorV2,implicitly[ExecutionContext]).orNotFound - + val serviceV2 = + MAuthMiddleware.httpRoutes[IO](requestValidationTimeout)(route)(implicitly[Async[IO]], authenticatorV2, implicitly[ExecutionContext]).orNotFound test("allow successfully authenticated request") { - val res = service(Request[IO](GET,uri"/").withHeaders( - MAuthRequest.X_MWS_TIME_HEADER_NAME -> timeHeader.toString, - MAuthRequest.X_MWS_AUTHENTICATION_HEADER_NAME -> authHeader - )) + val res = service( + Request[IO](GET, uri"/").withHeaders( + MAuthRequest.X_MWS_TIME_HEADER_NAME -> timeHeader.toString, + MAuthRequest.X_MWS_AUTHENTICATION_HEADER_NAME -> authHeader + ) + ) res.map(_.status).assertEquals(Status.Ok) } test("allow successfully authenticated request with both v1 and v2 headers, with V2 headers taking precedence") { - val res = service(Request[IO](GET,uri"/").withHeaders( - MAuthRequest.MCC_TIME_HEADER_NAME -> timeHeader.toString, - MAuthRequest.MCC_AUTHENTICATION_HEADER_NAME -> authHeaderV2, - MAuthRequest.X_MWS_TIME_HEADER_NAME -> (timeHeader - requestValidationTimeout.toSeconds - 10).toString, - MAuthRequest.X_MWS_AUTHENTICATION_HEADER_NAME -> "invalid auth header" - )) + val res = service( + Request[IO](GET, uri"/").withHeaders( + MAuthRequest.MCC_TIME_HEADER_NAME -> timeHeader.toString, + MAuthRequest.MCC_AUTHENTICATION_HEADER_NAME -> authHeaderV2, + MAuthRequest.X_MWS_TIME_HEADER_NAME -> (timeHeader - requestValidationTimeout.toSeconds - 10).toString, + MAuthRequest.X_MWS_AUTHENTICATION_HEADER_NAME -> "invalid auth header" + ) + ) res.map(_.status).assertEquals(Status.Ok) } test("allow successfully authenticated request with both v1 and v2 headers, fallback to v1 if v2 failed") { - val res = service(Request[IO](GET,uri"/").withHeaders( - MAuthRequest.MCC_TIME_HEADER_NAME -> timeHeader.toString, - MAuthRequest.MCC_AUTHENTICATION_HEADER_NAME -> wrongAuthHeaderV2, - MAuthRequest.X_MWS_TIME_HEADER_NAME -> timeHeader.toString, - MAuthRequest.X_MWS_AUTHENTICATION_HEADER_NAME -> authHeader - )) + val res = service( + Request[IO](GET, uri"/").withHeaders( + MAuthRequest.MCC_TIME_HEADER_NAME -> timeHeader.toString, + MAuthRequest.MCC_AUTHENTICATION_HEADER_NAME -> wrongAuthHeaderV2, + MAuthRequest.X_MWS_TIME_HEADER_NAME -> timeHeader.toString, + MAuthRequest.X_MWS_AUTHENTICATION_HEADER_NAME -> authHeader + ) + ) res.map(_.status).assertEquals(Status.Ok) } test("reject request if validation times out") { - val res = service(Request[IO](GET,uri"/").withHeaders( - MAuthRequest.X_MWS_TIME_HEADER_NAME -> (timeHeader - requestValidationTimeout.toSeconds - 10).toString, - MAuthRequest.X_MWS_AUTHENTICATION_HEADER_NAME -> authHeader - )) - - res.redeem({ - case e if e.isInstanceOf[MAuthValidationException] => true // TODO: fix removing the throwing of random Exceptions - case _ => false // any other exception shouldn't be thrown - }, - _ => false - ).assert + val res = service( + Request[IO](GET, uri"/").withHeaders( + MAuthRequest.X_MWS_TIME_HEADER_NAME -> (timeHeader - requestValidationTimeout.toSeconds - 10).toString, + MAuthRequest.X_MWS_AUTHENTICATION_HEADER_NAME -> authHeader + ) + ) + + res + .redeem( + { + case e if e.isInstanceOf[MAuthValidationException] => true // TODO: fix removing the throwing of random Exceptions + case _ => false // any other exception shouldn't be thrown + }, + _ => false + ) + .assert } test("reject if public key cannot be found") { @@ -133,102 +143,125 @@ class MAuthMiddlewareSuite extends CatsEffectSuite { override def getPublicKey(appUUID: UUID): Future[Option[PublicKey]] = if (appUUID == appUuid) { Future(none) - } - else Future.failed(new Throwable("Wrong app UUID")) + } else Future.failed(new Throwable("Wrong app UUID")) override def getPublicKeyIO(appUUID: UUID): IO[Option[PublicKey]] = ??? } val localAuthenticator: RequestAuthenticator = new RequestAuthenticator(localClient, epochTimeProvider) - val localService = MAuthMiddleware.httpRoutes[IO](requestValidationTimeout)(route)(implicitly[Async[IO]], localAuthenticator,implicitly[ExecutionContext]).orNotFound + val localService = + MAuthMiddleware.httpRoutes[IO](requestValidationTimeout)(route)(implicitly[Async[IO]], localAuthenticator, implicitly[ExecutionContext]).orNotFound - val res = localService(Request[IO](GET,uri"/").withHeaders( - MAuthRequest.X_MWS_TIME_HEADER_NAME -> timeHeader.toString, - MAuthRequest.X_MWS_AUTHENTICATION_HEADER_NAME -> authHeader - )) + val res = localService( + Request[IO](GET, uri"/").withHeaders( + MAuthRequest.X_MWS_TIME_HEADER_NAME -> timeHeader.toString, + MAuthRequest.X_MWS_AUTHENTICATION_HEADER_NAME -> authHeader + ) + ) res.map(_.status).assertEquals(Status.Unauthorized) } test("reject if Authentication header is missing") { - val res = service(Request[IO](GET,uri"/").withHeaders( - MAuthRequest.X_MWS_TIME_HEADER_NAME -> timeHeader.toString - )) + val res = service( + Request[IO](GET, uri"/").withHeaders( + MAuthRequest.X_MWS_TIME_HEADER_NAME -> timeHeader.toString + ) + ) res.map(_.status).assertEquals(Status.Unauthorized) } test("reject if Time header is missing") { - val res = service(Request[IO](GET,uri"/").withHeaders( - MAuthRequest.X_MWS_TIME_HEADER_NAME -> timeHeader.toString - )) + val res = service( + Request[IO](GET, uri"/").withHeaders( + MAuthRequest.X_MWS_TIME_HEADER_NAME -> timeHeader.toString + ) + ) res.map(_.status).assertEquals(Status.Unauthorized) } test("allow successfully authenticated request when authenticator supports v2 only with both v1 and v2 headers, with V2 headers taking precedence") { - val res = serviceV2(Request[IO](GET,uri"/").withHeaders( - MAuthRequest.MCC_TIME_HEADER_NAME -> timeHeader.toString, - MAuthRequest.MCC_AUTHENTICATION_HEADER_NAME -> authHeaderV2, - MAuthRequest.X_MWS_TIME_HEADER_NAME -> (timeHeader - requestValidationTimeout.toSeconds - 10).toString, - MAuthRequest.X_MWS_AUTHENTICATION_HEADER_NAME -> "invalid auth header" - )) + val res = serviceV2( + Request[IO](GET, uri"/").withHeaders( + MAuthRequest.MCC_TIME_HEADER_NAME -> timeHeader.toString, + MAuthRequest.MCC_AUTHENTICATION_HEADER_NAME -> authHeaderV2, + MAuthRequest.X_MWS_TIME_HEADER_NAME -> (timeHeader - requestValidationTimeout.toSeconds - 10).toString, + MAuthRequest.X_MWS_AUTHENTICATION_HEADER_NAME -> "invalid auth header" + ) + ) res.map(_.status).assertEquals(Status.Ok) } test("allow successfully authenticated request with V2 headers") { - val res = serviceV2(Request[IO](GET,uri"/").withHeaders( - MAuthRequest.MCC_TIME_HEADER_NAME -> timeHeader.toString, - MAuthRequest.MCC_AUTHENTICATION_HEADER_NAME -> authHeaderV2 - )) + val res = serviceV2( + Request[IO](GET, uri"/").withHeaders( + MAuthRequest.MCC_TIME_HEADER_NAME -> timeHeader.toString, + MAuthRequest.MCC_AUTHENTICATION_HEADER_NAME -> authHeaderV2 + ) + ) res.map(_.status).assertEquals(Status.Ok) } test("allow successfully authenticated request with V2 headers uppercase'd") { - val res = serviceV2(Request[IO](GET,uri"/").withHeaders( - MAuthRequest.MCC_TIME_HEADER_NAME -> timeHeader.toString, - MAuthRequest.MCC_AUTHENTICATION_HEADER_NAME.toUpperCase -> authHeaderV2 - )) + val res = serviceV2( + Request[IO](GET, uri"/").withHeaders( + MAuthRequest.MCC_TIME_HEADER_NAME -> timeHeader.toString, + MAuthRequest.MCC_AUTHENTICATION_HEADER_NAME.toUpperCase -> authHeaderV2 + ) + ) res.map(_.status).assertEquals(Status.Ok) } test("reject v2 request if it times out") { - val res = serviceV2(Request[IO](GET,uri"/").withHeaders( - MAuthRequest.MCC_TIME_HEADER_NAME -> (timeHeader - requestValidationTimeout.toSeconds - 10).toString, - MAuthRequest.MCC_AUTHENTICATION_HEADER_NAME -> authHeaderV2 - )) - - res.redeem({ - case e if e.isInstanceOf[MAuthValidationException] => true // TODO: fix removing the throwing of random Exceptions - case _ => false // any other exception shouldn't be thrown - }, - _ => false - ).assert + val res = serviceV2( + Request[IO](GET, uri"/").withHeaders( + MAuthRequest.MCC_TIME_HEADER_NAME -> (timeHeader - requestValidationTimeout.toSeconds - 10).toString, + MAuthRequest.MCC_AUTHENTICATION_HEADER_NAME -> authHeaderV2 + ) + ) + + res + .redeem( + { + case e if e.isInstanceOf[MAuthValidationException] => true // TODO: fix removing the throwing of random Exceptions + case _ => false // any other exception shouldn't be thrown + }, + _ => false + ) + .assert } test("reject v2 request if Authentication header is missing") { - val res = serviceV2(Request[IO](GET,uri"/").withHeaders( - MAuthRequest.MCC_TIME_HEADER_NAME -> timeHeader.toString - )) + val res = serviceV2( + Request[IO](GET, uri"/").withHeaders( + MAuthRequest.MCC_TIME_HEADER_NAME -> timeHeader.toString + ) + ) res.map(_.status).assertEquals(Status.Unauthorized) } test("reject v2 request if Time header is missing") { - val res = serviceV2(Request[IO](GET,uri"/").withHeaders( - MAuthRequest.MCC_AUTHENTICATION_HEADER_NAME -> authHeaderV2 - )) + val res = serviceV2( + Request[IO](GET, uri"/").withHeaders( + MAuthRequest.MCC_AUTHENTICATION_HEADER_NAME -> authHeaderV2 + ) + ) res.map(_.status).assertEquals(Status.Unauthorized) } test("reject if only v1 headers provided when authenticator is v2 only") { - val res = serviceV2(Request[IO](GET,uri"/").withHeaders( - MAuthRequest.X_MWS_TIME_HEADER_NAME -> timeHeader.toString, - MAuthRequest.X_MWS_AUTHENTICATION_HEADER_NAME -> authHeader - )) + val res = serviceV2( + Request[IO](GET, uri"/").withHeaders( + MAuthRequest.X_MWS_TIME_HEADER_NAME -> timeHeader.toString, + MAuthRequest.X_MWS_AUTHENTICATION_HEADER_NAME -> authHeader + ) + ) res.map(_.status).assertEquals(Status.Unauthorized) } From 15ce0e8f6fdc4216540581e00f5b5c5932f84ffc Mon Sep 17 00:00:00 2001 From: Francesco Serra Date: Fri, 29 Jul 2022 12:44:09 +0200 Subject: [PATCH 3/7] scalafmt build.sbt --- build.sbt | 5 ++--- project/Dependencies.scala | 10 +++++----- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/build.sbt b/build.sbt index 09954f3c..d6fabaf9 100644 --- a/build.sbt +++ b/build.sbt @@ -145,20 +145,19 @@ lazy val `mauth-authenticator-akka-http` = scalaModuleProject("mauth-authenticat ) lazy val `mauth-authenticator-http4s` = (project in file("modules/mauth-authenticator-http4s")) // don't need to cross-compile - .dependsOn(`mauth-authenticator-scala`,`mauth-test-utils` % "test") + .dependsOn(`mauth-authenticator-scala`, `mauth-test-utils` % "test") .settings( basicSettings, moduleName := "mauth-authenticator-http4s", publishSettings, testFrameworks += new TestFramework("munit.Framework"), - libraryDependencies ++= + libraryDependencies ++= Dependencies.provided(http4s) ++ Dependencies.compile(enumeratum) ++ Dependencies.compile(log4cats) ++ Dependencies.test(munitAndScalacheckForHttp4s: _*) ) - lazy val `mauth-jvm-clients` = (project in file(".")) .aggregate( `mauth-authenticator`, diff --git a/project/Dependencies.scala b/project/Dependencies.scala index c6b580d8..980bde78 100644 --- a/project/Dependencies.scala +++ b/project/Dependencies.scala @@ -31,9 +31,9 @@ object Dependencies extends DependencyUtils { val sttpAkkaHttpBackend: ModuleID = "com.softwaremill.sttp.client3" %% "akka-http-backend" % Version.sttp val scalaLibCompat: ModuleID = "org.scala-lang.modules" %% "scala-collection-compat" % "2.4.3" val caffeine: ModuleID = "com.github.ben-manes.caffeine" % "caffeine" % "2.9.1" - val http4s: ModuleID = "org.http4s" %% "http4s-dsl" % Version.http4s - val enumeratum: ModuleID = "com.beachape" %% "enumeratum" % Version.enumeratum - val log4cats = "org.typelevel" %% "log4cats-slf4j" % Version.log4cats + val http4s: ModuleID = "org.http4s" %% "http4s-dsl" % Version.http4s + val enumeratum: ModuleID = "com.beachape" %% "enumeratum" % Version.enumeratum + val log4cats = "org.typelevel" %% "log4cats-slf4j" % Version.log4cats // TEST DEPENDENCIES val akkaHttpTestKit: Seq[ModuleID] = Seq( @@ -47,8 +47,8 @@ object Dependencies extends DependencyUtils { val wiremock: ModuleID = "com.github.tomakehurst" % "wiremock" % "2.27.2" val munitAndScalacheckForHttp4s: Seq[ModuleID] = Seq( - "org.typelevel" %% "discipline-munit" % "1.0.9", - "org.typelevel" %% "munit-cats-effect-3" % "1.0.7", + "org.typelevel" %% "discipline-munit" % "1.0.9", + "org.typelevel" %% "munit-cats-effect-3" % "1.0.7", "org.typelevel" %% "scalacheck-effect-munit" % "1.0.4" ) From 08fa94ef735d71d1d424a0756dc8e0571ee39a70 Mon Sep 17 00:00:00 2001 From: Francesco Serra Date: Fri, 29 Jul 2022 12:48:43 +0200 Subject: [PATCH 4/7] remove unused imports --- .../src/main/scala/com/mdsol/mauth/http4s/MAuthMiddleware.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/mauth-authenticator-http4s/src/main/scala/com/mdsol/mauth/http4s/MAuthMiddleware.scala b/modules/mauth-authenticator-http4s/src/main/scala/com/mdsol/mauth/http4s/MAuthMiddleware.scala index 5b1c1cdb..b576a07a 100644 --- a/modules/mauth-authenticator-http4s/src/main/scala/com/mdsol/mauth/http4s/MAuthMiddleware.scala +++ b/modules/mauth-authenticator-http4s/src/main/scala/com/mdsol/mauth/http4s/MAuthMiddleware.scala @@ -5,7 +5,7 @@ import cats.data.{Kleisli, OptionT} import cats.effect.Sync import cats.syntax.all._ import cats.effect.kernel.Async -import cats.{~>, Monad, MonadThrow} +import cats.~> import com.mdsol.mauth.MAuthRequest import com.mdsol.mauth.scaladsl.Authenticator import org.http4s.{Http, HttpApp, HttpRoutes, Response, Status} From 393dc192ececc61aa52a721f83c201bb19663ee4 Mon Sep 17 00:00:00 2001 From: Francesco Serra Date: Fri, 29 Jul 2022 13:13:44 +0200 Subject: [PATCH 5/7] skip mima for new module --- build.sbt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/build.sbt b/build.sbt index d6fabaf9..7675551e 100644 --- a/build.sbt +++ b/build.sbt @@ -155,7 +155,8 @@ lazy val `mauth-authenticator-http4s` = (project in file("modules/mauth-authenti Dependencies.provided(http4s) ++ Dependencies.compile(enumeratum) ++ Dependencies.compile(log4cats) ++ - Dependencies.test(munitAndScalacheckForHttp4s: _*) + Dependencies.test(munitAndScalacheckForHttp4s: _*), + mimaPreviousArtifacts := Set.empty ) lazy val `mauth-jvm-clients` = (project in file(".")) From 70f58c0a1fa1aaf7776ee8e22d4658780faad60c Mon Sep 17 00:00:00 2001 From: Francesco Serra Date: Fri, 29 Jul 2022 17:23:44 +0200 Subject: [PATCH 6/7] remove getPublicKeyIO and some unused deps --- build.sbt | 2 +- .../mdsol/mauth/http4s/MAuthMiddlewareSuite.scala | 2 -- .../scaladsl/utils/ClientPublicKeyProvider.scala | 4 ---- project/Dependencies.scala | 15 +++++---------- 4 files changed, 6 insertions(+), 17 deletions(-) diff --git a/build.sbt b/build.sbt index 7675551e..0e4016ed 100644 --- a/build.sbt +++ b/build.sbt @@ -155,7 +155,7 @@ lazy val `mauth-authenticator-http4s` = (project in file("modules/mauth-authenti Dependencies.provided(http4s) ++ Dependencies.compile(enumeratum) ++ Dependencies.compile(log4cats) ++ - Dependencies.test(munitAndScalacheckForHttp4s: _*), + Dependencies.test(munitCatsEffect), mimaPreviousArtifacts := Set.empty ) diff --git a/modules/mauth-authenticator-http4s/src/test/scala/com/mdsol/mauth/http4s/MAuthMiddlewareSuite.scala b/modules/mauth-authenticator-http4s/src/test/scala/com/mdsol/mauth/http4s/MAuthMiddlewareSuite.scala index 36a19f08..8ca2edd5 100644 --- a/modules/mauth-authenticator-http4s/src/test/scala/com/mdsol/mauth/http4s/MAuthMiddlewareSuite.scala +++ b/modules/mauth-authenticator-http4s/src/test/scala/com/mdsol/mauth/http4s/MAuthMiddlewareSuite.scala @@ -67,7 +67,6 @@ class MAuthMiddlewareSuite extends CatsEffectSuite { if (appUUID == appUuid) { Future(publicKey.some) } else Future.failed(new Throwable("Wrong app UUID")) - override def getPublicKeyIO(appUUID: UUID): IO[Option[PublicKey]] = ??? } private val epochTimeProvider = new EpochTimeProvider { @@ -144,7 +143,6 @@ class MAuthMiddlewareSuite extends CatsEffectSuite { if (appUUID == appUuid) { Future(none) } else Future.failed(new Throwable("Wrong app UUID")) - override def getPublicKeyIO(appUUID: UUID): IO[Option[PublicKey]] = ??? } val localAuthenticator: RequestAuthenticator = new RequestAuthenticator(localClient, epochTimeProvider) diff --git a/modules/mauth-authenticator-scala/src/main/scala/com/mdsol/mauth/scaladsl/utils/ClientPublicKeyProvider.scala b/modules/mauth-authenticator-scala/src/main/scala/com/mdsol/mauth/scaladsl/utils/ClientPublicKeyProvider.scala index 4dcf836d..87258849 100644 --- a/modules/mauth-authenticator-scala/src/main/scala/com/mdsol/mauth/scaladsl/utils/ClientPublicKeyProvider.scala +++ b/modules/mauth-authenticator-scala/src/main/scala/com/mdsol/mauth/scaladsl/utils/ClientPublicKeyProvider.scala @@ -1,7 +1,5 @@ package com.mdsol.mauth.scaladsl.utils -import cats.effect.IO - import java.security.PublicKey import java.util.UUID @@ -15,6 +13,4 @@ trait ClientPublicKeyProvider { * @return Future of { @link PublicKey} registered in MAuth for the application with given appUUID. */ def getPublicKey(appUUID: UUID): Future[Option[PublicKey]] - - def getPublicKeyIO(appUUID: UUID): IO[Option[PublicKey]] } diff --git a/project/Dependencies.scala b/project/Dependencies.scala index 980bde78..ae06e6ab 100644 --- a/project/Dependencies.scala +++ b/project/Dependencies.scala @@ -41,16 +41,11 @@ object Dependencies extends DependencyUtils { "com.typesafe.akka" %% "akka-testkit" % Version.akka, "com.typesafe.akka" %% "akka-stream-testkit" % Version.akka ) - val commonsIO: ModuleID = "commons-io" % "commons-io" % "2.8.0" - val scalaMock: ModuleID = "org.scalamock" %% "scalamock" % "5.1.0" - val scalaTest: ModuleID = "org.scalatest" %% "scalatest" % "3.2.7" - val wiremock: ModuleID = "com.github.tomakehurst" % "wiremock" % "2.27.2" - - val munitAndScalacheckForHttp4s: Seq[ModuleID] = Seq( - "org.typelevel" %% "discipline-munit" % "1.0.9", - "org.typelevel" %% "munit-cats-effect-3" % "1.0.7", - "org.typelevel" %% "scalacheck-effect-munit" % "1.0.4" - ) + val commonsIO: ModuleID = "commons-io" % "commons-io" % "2.8.0" + val scalaMock: ModuleID = "org.scalamock" %% "scalamock" % "5.1.0" + val scalaTest: ModuleID = "org.scalatest" %% "scalatest" % "3.2.7" + val wiremock: ModuleID = "com.github.tomakehurst" % "wiremock" % "2.27.2" + val munitCatsEffect: ModuleID = "org.typelevel" %% "munit-cats-effect-3" % "1.0.7" // Dependency Conflict Resolution val exclusions = Seq() From 7a3c57f97027ce6e6c69e353e247c56cbafe081f Mon Sep 17 00:00:00 2001 From: Francesco Serra Date: Fri, 29 Jul 2022 17:52:39 +0200 Subject: [PATCH 7/7] fix unused override --- .../com/mdsol/mauth/akka/http/MauthPublicKeyProvider.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/mauth-authenticator-akka-http/src/main/scala/com/mdsol/mauth/akka/http/MauthPublicKeyProvider.scala b/modules/mauth-authenticator-akka-http/src/main/scala/com/mdsol/mauth/akka/http/MauthPublicKeyProvider.scala index 183cf23c..53cd0cb8 100644 --- a/modules/mauth-authenticator-akka-http/src/main/scala/com/mdsol/mauth/akka/http/MauthPublicKeyProvider.scala +++ b/modules/mauth-authenticator-akka-http/src/main/scala/com/mdsol/mauth/akka/http/MauthPublicKeyProvider.scala @@ -45,7 +45,7 @@ class MauthPublicKeyProvider(configuration: AuthenticatorConfiguration, signer: override def getPublicKey(appUUID: UUID): Future[Option[PublicKey]] = getPublicKeyIO(appUUID).unsafeToFuture() - override def getPublicKeyIO(appUUID: UUID): IO[Option[PublicKey]] = memoizeF(Some(configuration.getTimeToLive.seconds)) { + def getPublicKeyIO(appUUID: UUID): IO[Option[PublicKey]] = memoizeF(Some(configuration.getTimeToLive.seconds)) { val signedRequest = signer.signRequest(UnsignedRequest.noBody("GET", new URI(configuration.getBaseUrl + getRequestUrlPath(appUUID)), headers = Map.empty)) retrievePublicKey()(IO.fromFuture(IO(HttpClient.call(signedRequest.toAkkaHttpRequest)))) }