Skip to content

Commit

Permalink
Merge pull request #4 from permutive-engineering/feature/support-scal…
Browse files Browse the repository at this point in the history
…a-2.12

Add support for Scala 2.12
  • Loading branch information
alejandrohdezma authored Jan 10, 2024
2 parents bf0df24 + 634b51b commit 2395cd9
Show file tree
Hide file tree
Showing 9 changed files with 42 additions and 49 deletions.
2 changes: 2 additions & 0 deletions .github/docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion build.sbt
Original file line number Diff line number Diff line change
@@ -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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@

package com.permutive.gcp.auth.pureconfig

import scala.util.chaining._

import cats.effect.IO
import cats.effect.Resource

Expand Down Expand Up @@ -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)
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand All @@ -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]
Expand All @@ -72,15 +72,15 @@ 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]
.readUtf8(defaultCredentialsFile)
.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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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)

Expand All @@ -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.
Expand All @@ -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.
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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.
Expand All @@ -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)

}
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@

package com.permutive.gcp.auth

import scala.util.chaining._

import cats.effect.IO
import cats.effect.kernel.Resource

Expand Down Expand Up @@ -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]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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._
Expand Down Expand Up @@ -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"
Expand Down
4 changes: 2 additions & 2 deletions project/plugins.sbt
Original file line number Diff line number Diff line change
@@ -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")
Expand Down

0 comments on commit 2395cd9

Please sign in to comment.