Skip to content

Commit

Permalink
Replace Spray JWT dependency (#3030)
Browse files Browse the repository at this point in the history
  • Loading branch information
ennru authored Oct 24, 2023
1 parent c5a3c7c commit 917822f
Show file tree
Hide file tree
Showing 4 changed files with 86 additions and 5 deletions.
3 changes: 2 additions & 1 deletion build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,8 @@ lazy val googleCommon = alpakkaProject(
"google-common",
"google.common",
Dependencies.GoogleCommon,
Test / fork := true
Test / fork := true,
headerSources / excludeFilter := HiddenFileFilter || "JwtSprayJsonParser.scala"
)

lazy val googleCloudBigQuery = alpakkaProject(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import akka.stream.Materializer
import akka.stream.alpakka.google.http.GoogleHttp
import akka.stream.alpakka.google.{implicits, RequestSettings}
import pdi.jwt.JwtAlgorithm.RS256
import pdi.jwt.{JwtClaim, JwtSprayJson}
import pdi.jwt.JwtClaim
import spray.json.DefaultJsonProtocol._
import spray.json.JsonFormat

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/*
* This software is licensed under the Apache 2 license.
* Copyright 2021 JWT-Scala Contributors.
*
* Copyright (C) since 2023 Lightbend Inc. <https://www.lightbend.com>
*/

package akka.stream.alpakka.google.auth

import akka.annotation.InternalApi
import pdi.jwt.{JwtAlgorithm, JwtClaim, JwtHeader, JwtJsonCommon}

import java.time.Clock
import pdi.jwt.exceptions.JwtNonStringException
import spray.json._

/**
* Implementation of `JwtCore` using `JsObject` from spray-json.
*
* This class originally came from jwt-spray-json,
* but was removed in https://github.com/jwt-scala/jwt-scala/commit/bf1131ce02480103c0b953b97da001105a3ee038
*/
@InternalApi
private[auth] trait JwtSprayJsonParser[H, C] extends JwtJsonCommon[JsObject, H, C] {
protected def parse(value: String): JsObject = value.parseJson.asJsObject

protected def stringify(value: JsObject): String = value.compactPrint

protected def getAlgorithm(header: JsObject): Option[JwtAlgorithm] =
header.fields.get("alg").flatMap {
case JsString("none") => None
case JsString(algo) => Option(JwtAlgorithm.fromString(algo))
case JsNull => None
case _ => throw new JwtNonStringException("alg")
}

}

@InternalApi
private[auth] object JwtSprayJson extends JwtSprayJson(Clock.systemUTC) {
def apply(clock: Clock): JwtSprayJson = new JwtSprayJson(clock)
}

@InternalApi
private[auth] class JwtSprayJson(override val clock: Clock) extends JwtSprayJsonParser[JwtHeader, JwtClaim] {

import DefaultJsonProtocol._
override def parseHeader(header: String): JwtHeader = {
val jsObj = parse(header)
JwtHeader(
algorithm = getAlgorithm(jsObj),
typ = safeGetField[String](jsObj, "typ"),
contentType = safeGetField[String](jsObj, "cty"),
keyId = safeGetField[String](jsObj, "kid")
)
}

override def parseClaim(claim: String): JwtClaim = {
val jsObj = parse(claim)
val content = JsObject(jsObj.fields - "iss" - "sub" - "aud" - "exp" - "nbf" - "iat" - "jti")
JwtClaim(
content = stringify(content),
issuer = safeGetField[String](jsObj, "iss"),
subject = safeGetField[String](jsObj, "sub"),
audience = safeGetField[Set[String]](jsObj, "aud")
.orElse(safeGetField[String](jsObj, "aud").map(s => Set(s))),
expiration = safeGetField[Long](jsObj, "exp"),
notBefore = safeGetField[Long](jsObj, "nbf"),
issuedAt = safeGetField[Long](jsObj, "iat"),
jwtId = safeGetField[String](jsObj, "jti")
)
}

private[this] def safeRead[A: JsonReader](js: JsValue) =
safeReader[A].read(js).fold(_ => None, a => Option(a))

private[this] def safeGetField[A: JsonReader](js: JsObject, name: String) =
js.fields.get(name).flatMap(safeRead[A])
}
7 changes: 4 additions & 3 deletions project/Dependencies.scala
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ object Dependencies {
val CouchbaseVersion = "2.7.16"
val CouchbaseVersionForDocs = "2.7"

val JwtCoreVersion = "3.0.1"
// https://github.com/jwt-scala/jwt-scala/releases
val JwtScalaVersion = "9.4.4"

val log4jOverSlf4jVersion = "1.7.36"
val jclOverSlf4jVersion = "1.7.36"
Expand Down Expand Up @@ -204,7 +205,7 @@ object Dependencies {
libraryDependencies ++= Seq(
"com.typesafe.akka" %% "akka-http" % AkkaHttpVersion,
"com.typesafe.akka" %% "akka-http-spray-json" % AkkaHttpVersion,
"com.github.jwt-scala" %% "jwt-spray-json" % "9.0.2", // ApacheV2
"com.github.jwt-scala" %% "jwt-json-common" % JwtScalaVersion,
// https://github.com/googleapis/google-auth-library-java
"com.google.auth" % "google-auth-library-credentials" % GoogleAuthVersion,
"io.specto" % "hoverfly-java" % hoverflyVersion % Test // ApacheV2
Expand Down Expand Up @@ -304,7 +305,7 @@ object Dependencies {
libraryDependencies ++= Seq(
"com.typesafe.akka" %% "akka-http" % AkkaHttpVersion,
"com.typesafe.akka" %% "akka-http-spray-json" % AkkaHttpVersion,
"com.github.jwt-scala" %% "jwt-spray-json" % "7.1.4" // ApacheV2
"com.github.jwt-scala" %% "jwt-json-common" % JwtScalaVersion
) ++ Mockito
)

Expand Down

0 comments on commit 917822f

Please sign in to comment.