diff --git a/.github/docs/README.md b/.github/docs/README.md index c5e324a..c141bd8 100644 --- a/.github/docs/README.md +++ b/.github/docs/README.md @@ -11,6 +11,8 @@ Add the following line to your `build.sbt` file: libraryDependencies += "@ORGANIZATION@" %% "@NAME@" % "@VERSION@" ``` +The library is published for Scala versions: @SUPPORTED_SCALA_VERSIONS@. + ## Usage This library provides a class `TokenProvider` that is able to retrieve a diff --git a/build.sbt b/build.sbt index a0d20a3..61ce645 100644 --- a/build.sbt +++ b/build.sbt @@ -1,5 +1,5 @@ ThisBuild / scalaVersion := "2.13.12" -ThisBuild / crossScalaVersions := Seq("2.13.12", "3.3.1") +ThisBuild / crossScalaVersions := Seq("2.12.18", "2.13.12", "3.3.1") ThisBuild / organization := "com.permutive" ThisBuild / versionPolicyIntention := Compatibility.BinaryAndSourceCompatible diff --git a/modules/gcp-auth-pureconfig/src/test/scala/com/permutive/gcp/auth/pureconfig/TypeTokenSuite.scala b/modules/gcp-auth-pureconfig/src/test/scala/com/permutive/gcp/auth/pureconfig/TypeTokenSuite.scala index ecf4601..67a0ca9 100644 --- a/modules/gcp-auth-pureconfig/src/test/scala/com/permutive/gcp/auth/pureconfig/TypeTokenSuite.scala +++ b/modules/gcp-auth-pureconfig/src/test/scala/com/permutive/gcp/auth/pureconfig/TypeTokenSuite.scala @@ -16,8 +16,6 @@ package com.permutive.gcp.auth.pureconfig -import scala.util.chaining._ - import cats.effect.IO import cats.effect.Resource @@ -88,8 +86,10 @@ class TypeTokenSuite extends ClientSuite { implicit val ConfigConfigReader: ConfigReader[Config] = ConfigReader.forProduct1("token-type")(Config.apply) - def fixture(resource: String) = Resource.make { - IO(sys.props("user.home")).flatTap(_ => IO(sys.props.put("user.home", getClass.getResource(resource).getPath()))) - }(userHome => IO(sys.props.put("user.home", userHome)).void).pipe(ResourceFixture(_)) + def fixture(resource: String) = ResourceFixture { + Resource.make { + IO(sys.props("user.home")).flatTap(_ => IO(sys.props.put("user.home", getClass.getResource(resource).getPath()))) + }(userHome => IO(sys.props.put("user.home", userHome)).void) + } } diff --git a/modules/gcp-auth/src/main/scala/com/permutive/gcp/auth/Parser.scala b/modules/gcp-auth/src/main/scala/com/permutive/gcp/auth/Parser.scala index 9680fb7..024b615 100644 --- a/modules/gcp-auth/src/main/scala/com/permutive/gcp/auth/Parser.scala +++ b/modules/gcp-auth/src/main/scala/com/permutive/gcp/auth/Parser.scala @@ -48,7 +48,7 @@ private[auth] object Parser { .compile .onlyOrError .map(line => RefreshToken(line.trim())) - .adaptError(_ => new EmptyRefreshTokenFile(path)) + .adaptError { case _ => new EmptyRefreshTokenFile(path) } final def googleClientSecrets[F[_]: Files: Concurrent](path: Path): F[(ClientId, ClientSecret)] = Files[F] @@ -60,7 +60,7 @@ private[auth] object Parser { .flatMap { installed => (installed.get[ClientId]("client_id"), installed.get[ClientSecret]("client_secret")).tupled.liftTo[F] } - .adaptError(new UnableToGetClientSecrets(path, _)) + .adaptError { case t => new UnableToGetClientSecrets(path, t) } final def googleServiceAccount[F[_]: Files: Sync](path: Path): F[(ClientEmail, RSAPrivateKey)] = Files[F] @@ -72,7 +72,7 @@ private[auth] object Parser { (json.hcursor.get[ClientEmail]("client_email"), json.hcursor.get[String]("private_key")).tupled.liftTo[F] } .flatMap(_.traverse(loadPrivateKey[F])) - .adaptError(new UnableToGetClientData(path, _)) + .adaptError { case t => new UnableToGetClientData(path, t) } final def applicationDefaultCredentials[F[_]: Concurrent: Files]: F[(ClientId, ClientSecret, RefreshToken)] = Files[F] @@ -80,7 +80,7 @@ private[auth] object Parser { .compile .string .flatMap(parser.decode[(ClientId, ClientSecret, RefreshToken)](_).liftTo[F]) - .adaptError(new UnableToGetDefaultCredentials(defaultCredentialsFile, _)) + .adaptError { case t => new UnableToGetDefaultCredentials(defaultCredentialsFile, t) } implicit private val decodeCredentials: Decoder[(ClientId, ClientSecret, RefreshToken)] = c => (c.get[ClientId]("client_id"), c.get[ClientSecret]("client_secret"), c.get[RefreshToken]("refresh_token")).tupled diff --git a/modules/gcp-auth/src/main/scala/com/permutive/gcp/auth/TokenProvider.scala b/modules/gcp-auth/src/main/scala/com/permutive/gcp/auth/TokenProvider.scala index e20d8b5..68666a4 100644 --- a/modules/gcp-auth/src/main/scala/com/permutive/gcp/auth/TokenProvider.scala +++ b/modules/gcp-auth/src/main/scala/com/permutive/gcp/auth/TokenProvider.scala @@ -21,11 +21,9 @@ import java.time.Duration import java.time.Instant import java.util.Date -import scala.annotation.nowarn import scala.concurrent.duration._ import cats.Applicative -import cats.ApplicativeThrow import cats.effect.Async import cats.effect.Clock import cats.effect.Concurrent @@ -50,13 +48,12 @@ import com.permutive.refreshable.Refreshable import fs2.io.file.Files import fs2.io.file.Path import org.http4s.Header -import org.http4s.Method import org.http4s.Method.GET import org.http4s.Method.POST +import org.http4s.Request import org.http4s.Uri import org.http4s.UrlForm import org.http4s.client.Client -import org.http4s.client.dsl.MethodOps import org.http4s.syntax.all._ import org.typelevel.ci._ import pdi.jwt.JwtCirce @@ -166,11 +163,10 @@ object TokenProvider { */ def identity[F[_]: Concurrent: Clock](httpClient: Client[F], audience: Uri): TokenProvider[F] = TokenProvider.create { - val request = GET( - uri"http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/identity" +? - ("audience" -> audience), - Header.Raw(ci"Metadata-Flavor", "Google") - ) + val uri = uri"http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/identity" +? + ("audience" -> audience) + + val request = Request[F](GET, uri).putHeaders(Header.Raw(ci"Metadata-Flavor", "Google")) val jwtOptions = JwtOptions(signature = false) @@ -183,7 +179,7 @@ object TokenProvider { .map(ExpiresIn(_)) .map(AccessToken(Token(token), _)) } - .adaptError(new UnableToGetToken(_)) + .adaptError { case t => new UnableToGetToken(t) } } /** Retrieves a workload service account token using Google's metadata server. @@ -199,14 +195,13 @@ object TokenProvider { */ def serviceAccount[F[_]: Concurrent](httpClient: Client[F]): TokenProvider[F] = TokenProvider.create { + val request = + Request[F](GET, uri"http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token") + .putHeaders(Header.Raw(ci"Metadata-Flavor", "Google")) + httpClient - .expect[AccessToken] { - GET( - uri"http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token", - Header.Raw(ci"Metadata-Flavor", "Google") - ) - } - .adaptError(new UnableToGetToken(_)) + .expect[AccessToken](request) + .adaptError { case t => new UnableToGetToken(t) } } /** Retrieves a service account token from Google's OAuth API. @@ -250,9 +245,9 @@ object TokenProvider { .sign(Algorithm.RSA256(privateKey)) } .map(token => UrlForm("grant_type" -> "urn:ietf:params:oauth:grant-type:jwt-bearer", "assertion" -> token)) - .map(POST(_, uri"https://oauth2.googleapis.com/token")) + .map(Request[F](POST, uri"https://oauth2.googleapis.com/token").withEntity(_)) .flatMap(httpClient.expect[AccessToken](_)) - .adaptError(new UnableToGetToken(_)) + .adaptError { case t => new UnableToGetToken(t) } } /** Retrieves a user account token from Google's OAuth API. @@ -295,9 +290,11 @@ object TokenProvider { "grant_type" -> "refresh_token" ) + val request = Request[F](POST, uri"https://oauth2.googleapis.com/token").withEntity(form) + httpClient - .expect[AccessToken](POST(form, uri"https://oauth2.googleapis.com/token")) - .adaptError(new UnableToGetToken(_)) + .expect[AccessToken](request) + .adaptError { case t => new UnableToGetToken(t) } } /** Retrieves a user account token from Google's OAuth API using the "Application Default Credentials" file. @@ -322,9 +319,4 @@ object TokenProvider { def const[F[_]: Applicative](token: AccessToken): TokenProvider[F] = TokenProvider.create(token.pure) - @nowarn - @SuppressWarnings(Array("scalafix:DisableSyntax.implicitConversion")) - implicit private def http4sClientSyntaxMethod[F[_]: ApplicativeThrow](method: Method): MethodOps[F] = - new MethodOps[F](method) - } diff --git a/modules/gcp-auth/src/main/scala/com/permutive/gcp/auth/models/AccessToken.scala b/modules/gcp-auth/src/main/scala/com/permutive/gcp/auth/models/AccessToken.scala index afc056a..2c63308 100644 --- a/modules/gcp-auth/src/main/scala/com/permutive/gcp/auth/models/AccessToken.scala +++ b/modules/gcp-auth/src/main/scala/com/permutive/gcp/auth/models/AccessToken.scala @@ -19,7 +19,6 @@ package com.permutive.gcp.auth.models import cats.effect.Concurrent import cats.syntax.all._ -import com.permutive.gcp.auth.models.ExpiresIn import io.circe.Decoder import org.http4s.AuthScheme import org.http4s.Credentials diff --git a/modules/gcp-auth/src/test/scala/com/permutive/gcp/auth/ParserSuite.scala b/modules/gcp-auth/src/test/scala/com/permutive/gcp/auth/ParserSuite.scala index 46ff4a4..70bd988 100644 --- a/modules/gcp-auth/src/test/scala/com/permutive/gcp/auth/ParserSuite.scala +++ b/modules/gcp-auth/src/test/scala/com/permutive/gcp/auth/ParserSuite.scala @@ -16,8 +16,6 @@ package com.permutive.gcp.auth -import scala.util.chaining._ - import cats.effect.IO import cats.effect.kernel.Resource @@ -173,9 +171,11 @@ class ParserSuite extends CatsEffectSuite { // Parser.applicationDefaultCredentials // ////////////////////////////////////////// - def fixture(resource: String) = Resource.make { - IO(sys.props("user.home")).flatTap(_ => IO(sys.props.put("user.home", getClass.getResource(resource).getPath()))) - }(userHome => IO(sys.props.put("user.home", userHome)).void).pipe(ResourceFixture(_)) + def fixture(resource: String) = ResourceFixture { + Resource.make { + IO(sys.props("user.home")).flatTap(_ => IO(sys.props.put("user.home", getClass.getResource(resource).getPath()))) + }(userHome => IO(sys.props.put("user.home", userHome)).void) + } fixture("/default/valid").test("Parser.applicationDefaultCredentials should parse a valid file") { _ => val result = Parser.applicationDefaultCredentials[IO] diff --git a/modules/gcp-auth/src/test/scala/com/permutive/gcp/auth/TokenProviderSuite.scala b/modules/gcp-auth/src/test/scala/com/permutive/gcp/auth/TokenProviderSuite.scala index b7a58e9..dd33d6f 100644 --- a/modules/gcp-auth/src/test/scala/com/permutive/gcp/auth/TokenProviderSuite.scala +++ b/modules/gcp-auth/src/test/scala/com/permutive/gcp/auth/TokenProviderSuite.scala @@ -20,8 +20,6 @@ import java.security.KeyPairGenerator import java.security.interfaces.RSAPrivateKey import java.time.Instant -import scala.util.chaining._ - import cats.effect.IO import cats.effect.Resource import cats.syntax.all._ @@ -232,9 +230,11 @@ class TokenProviderSuite extends ClientSuite { // TokenProvider.userAccount(Client) // /////////////////////////////////////// - def fixture(resource: String) = Resource.make { - IO(sys.props("user.home")).flatTap(_ => IO(sys.props.put("user.home", getClass.getResource(resource).getPath()))) - }(userHome => IO(sys.props.put("user.home", userHome)).void).pipe(ResourceFixture(_)) + def fixture(resource: String) = ResourceFixture { + Resource.make { + IO(sys.props("user.home")).flatTap(_ => IO(sys.props.put("user.home", getClass.getResource(resource).getPath()))) + }(userHome => IO(sys.props.put("user.home", userHome)).void) + } fixture("/default/valid").test { "TokenProvider.userAccount(Client) retrieves token successfully" diff --git a/project/plugins.sbt b/project/plugins.sbt index 0df7c47..ed5d297 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -1,8 +1,8 @@ addSbtPlugin("ch.epfl.scala" % "sbt-scalafix" % "0.11.1") addSbtPlugin("com.alejandrohdezma" % "sbt-ci" % "2.14.0") addSbtPlugin("com.alejandrohdezma" % "sbt-fix" % "0.7.1") -addSbtPlugin("com.alejandrohdezma" % "sbt-github-mdoc" % "0.11.12") -addSbtPlugin("com.alejandrohdezma" % "sbt-github-header" % "0.11.12") +addSbtPlugin("com.alejandrohdezma" % "sbt-github-mdoc" % "0.11.13") +addSbtPlugin("com.alejandrohdezma" % "sbt-github-header" % "0.11.13") addSbtPlugin("com.alejandrohdezma" % "sbt-scalafix-defaults" % "0.11.0") addSbtPlugin("com.alejandrohdezma" % "sbt-scalafmt-defaults" % "0.9.0") addSbtPlugin("com.alejandrohdezma" % "sbt-mdoc-toc" % "0.4.1")