All Downloads are FREE. Search and download functionalities are using the official Maven repository.

tsec.jws.mac.JWTMac.scala Maven / Gradle / Ivy

The newest version!
package tsec.jws.mac

import java.time.Instant

import cats.Eq
import cats.effect.Sync
import cats.syntax.all._
import tsec.common._
import tsec.jws.{JWSJWT, JWSSerializer}
import tsec.jwt.JWTClaims
import tsec.jwt.algorithms.JWTMacAlgo
import tsec.mac._
import tsec.mac.jca.{MacErrorM, MacSigningKey}

sealed abstract case class JWTMac[A](header: JWSMacHeader[A], body: JWTClaims, signature: MAC[A])
    extends JWSJWT[A, MAC] {
  def toEncodedString(implicit hs: JWSSerializer[JWSMacHeader[A]]): String =
    hs.toB64URL(header) + "." + JWTClaims.toB64URL(body) + "." + signature.toB64UrlString

  def id = body.jwtId

  def ==(other: JWTMac[A]) =
    header == other.header &&
      body == other.body &&
      signature.toB64String == other.signature.toB64String

  override def equals(obj: Any): Boolean = obj match {
    case j: JWTMac[A] => ==(j)
    case _            => false
  }
}

object JWTMac {
  private[tsec] def buildToken[A](header: JWSMacHeader[A], claims: JWTClaims, signature: MAC[A]): JWTMac[A] =
    new JWTMac[A](header, claims, signature) {}

  /** Methods abstracted over F[_] */
  def build[F[_], A: JWTMacAlgo](
      claims: JWTClaims,
      key: MacSigningKey[A]
  )(implicit s: JWSMacCV[F, A], F: Sync[F]): F[JWTMac[A]] = {
    val header = JWSMacHeader[A]
    generateSignature[F, A](header, claims, key).map(sig => JWTMac.buildToken[A](header, claims, sig))
  }

  def generateSignature[F[_], A: JWTMacAlgo](
      header: JWSMacHeader[A],
      body: JWTClaims,
      key: MacSigningKey[A]
  )(
      implicit s: JWSMacCV[F, A],
      me: Sync[F]
  ): F[MAC[A]] = s.sign(header, body, key)

  def generateSignature[F[_], A: JWTMacAlgo](body: JWTClaims, key: MacSigningKey[A])(
      implicit s: JWSMacCV[F, A],
      me: Sync[F]
  ): F[MAC[A]] = s.sign(JWSMacHeader[A], body, key)

  def buildToString[F[_], A: JWTMacAlgo](
      header: JWSMacHeader[A],
      body: JWTClaims,
      key: MacSigningKey[A]
  )(implicit s: JWSMacCV[F, A], me: Sync[F]): F[String] = s.signToString(header, body, key)

  def buildToString[F[_], A: JWTMacAlgo](
      body: JWTClaims,
      key: MacSigningKey[A]
  )(implicit s: JWSMacCV[F, A], me: Sync[F]): F[String] = s.signToString(JWSMacHeader[A], body, key)

  def verifyBool[F[_], A: JWTMacAlgo](jwt: String, key: MacSigningKey[A])(
      implicit s: JWSMacCV[F, A],
      F: Sync[F]
  ): F[Boolean] = F.delay(Instant.now()).flatMap(s.verifyBool(jwt, key, _))

  def verify[F[_], A: JWTMacAlgo](jwt: String, key: MacSigningKey[A])(
      implicit s: JWSMacCV[F, A],
      F: Sync[F]
  ): F[VerificationStatus] = F.delay(Instant.now()).flatMap(s.verify(jwt, key, _))

  def verifyAndParse[F[_], A](jwt: String, key: MacSigningKey[A])(
      implicit s: JWSMacCV[F, A],
      F: Sync[F]
  ): F[JWTMac[A]] =
    F.delay(Instant.now()).flatMap(s.verifyAndParse(jwt, key, _))

  def verifyFromStringBool[F[_], A: JWTMacAlgo](jwt: String, key: MacSigningKey[A])(
      implicit s: JWSMacCV[F, A],
      F: Sync[F]
  ): F[Boolean] = F.delay(Instant.now()).flatMap(s.verifyBool(jwt, key, _))

  def verifyFromInstanceBool[F[_], A: JWTMacAlgo](jwt: JWTMac[A], key: MacSigningKey[A])(
      implicit hs: JWSSerializer[JWSMacHeader[A]],
      cv: JWSMacCV[F, A],
      F: Sync[F]
  ): F[Boolean] = F.delay(Instant.now()).flatMap(cv.verifyBool(jwt.toEncodedString, key, _))

  def verifyFromString[F[_], A: JWTMacAlgo](jwt: String, key: MacSigningKey[A])(
      implicit s: JWSMacCV[F, A],
      F: Sync[F]
  ): F[VerificationStatus] = F.delay(Instant.now()).flatMap(s.verify(jwt, key, _))

  def verifyFromInstance[F[_], A: JWTMacAlgo](jwt: JWTMac[A], key: MacSigningKey[A])(
      implicit hs: JWSSerializer[JWSMacHeader[A]],
      cv: JWSMacCV[F, A],
      F: Sync[F]
  ): F[VerificationStatus] = F.delay(Instant.now()).flatMap(cv.verify(jwt.toEncodedString, key, _))

  def toEncodedString[F[_], A: JWTMacAlgo](
      jwt: JWTMac[A]
  )(implicit s: JWSMacCV[F, A], me: Sync[F]): String = s.toEncodedString(jwt)

  def parseUnverified[F[_], A: JWTMacAlgo](
      jwt: String
  )(implicit s: JWSMacCV[F, A], me: Sync[F]): F[JWTMac[A]] = s.parseUnverified(jwt)
}

object JWTMacImpure {

  implicit def eq[A]: Eq[JWTMac[A]] = new Eq[JWTMac[A]] {
    def eqv(x: JWTMac[A], y: JWTMac[A]): Boolean =
      x.header == y.header &&
        x.body == y.body &&
        x.signature.toB64String == y.signature.toB64String
  }

  /** Default methods */
  def build[A: JWTMacAlgo](
      claims: JWTClaims,
      key: MacSigningKey[A]
  )(implicit s: JWSMacCV[MacErrorM, A]): MacErrorM[JWTMac[A]] =
    s.signAndBuild(JWSMacHeader[A], claims, key)

  /** Sign the header and the body with the given key, into a jwt object
    *
    * @param header the JWT header
    * @param body
    * @param key
    * @param s
    * @tparam A
    * @return
    */
  def generateSignature[A: JWTMacAlgo](header: JWSMacHeader[A], body: JWTClaims, key: MacSigningKey[A])(
      implicit s: JWSMacCV[MacErrorM, A]
  ): MacErrorM[MAC[A]] = s.sign(header, body, key)

  def generateSignature[A: JWTMacAlgo](body: JWTClaims, key: MacSigningKey[A])(
      implicit s: JWSMacCV[MacErrorM, A]
  ): MacErrorM[MAC[A]] =
    s.sign(JWSMacHeader[A], body, key)

  def buildToString[A: JWTMacAlgo](
      body: JWTClaims,
      key: MacSigningKey[A]
  )(implicit s: JWSMacCV[MacErrorM, A]): MacErrorM[String] = s.signToString(JWSMacHeader[A], body, key)

  def buildToString[A: JWTMacAlgo](
      header: JWSMacHeader[A],
      body: JWTClaims,
      key: MacSigningKey[A]
  )(implicit s: JWSMacCV[MacErrorM, A]): MacErrorM[String] = s.signToString(header, body, key)

  /** Verify the JWT
    *
    * @param jwt the JWT, as a string representation
    * @param key the signing key
    * @tparam A the signing algorithm
    * @return Signing output as a boolean or a MacError.
    *         Useful to detect any other errors aside from malformed input.
    */
  def verifyFromString[A: JWTMacAlgo](jwt: String, key: MacSigningKey[A])(
      implicit s: JWSMacCV[MacErrorM, A]
  ): MacErrorM[Boolean] = s.verifyBool(jwt, key, Instant.now)

  def verifyFromInstance[A: JWTMacAlgo](jwt: JWTMac[A], key: MacSigningKey[A])(
      implicit hs: JWSSerializer[JWSMacHeader[A]],
      cv: JWSMacCV[MacErrorM, A]
  ): MacErrorM[Boolean] = cv.verifyBool(jwt.toEncodedString, key, Instant.now)

  def verifyAndParse[A](jwt: String, key: MacSigningKey[A])(implicit s: JWSMacCV[MacErrorM, A]): MacErrorM[JWTMac[A]] =
    s.verifyAndParse(jwt, key, Instant.now)

  def toEncodedString[A: JWTMacAlgo](
      jwt: JWTMac[A]
  )(implicit s: JWSMacCV[MacErrorM, A]): String = s.toEncodedString(jwt)

  def parseUnverified[A: JWTMacAlgo](
      jwt: String
  )(implicit s: JWSMacCV[MacErrorM, A]): MacErrorM[JWTMac[A]] = s.parseUnverified(jwt)
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy