org.http4s.headers.Authorization Scala Examples

The following examples show how to use org.http4s.headers.Authorization. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example.
Example 1
Source File: HmacAuthMiddleware.scala    From iotchain   with MIT License 5 votes vote down vote up
package jbok.network.http.server.middleware

import java.time.{Duration, Instant}

import cats.data.{Kleisli, OptionT}
import cats.effect.Sync
import jbok.network.http.server.authentication.HMAC
import org.http4s.headers.Authorization
import org.http4s.util.CaseInsensitiveString
import org.http4s.{AuthScheme, Credentials, HttpRoutes, Request, Response, Status}
import tsec.mac.jca.{HMACSHA256, MacSigningKey}

import scala.concurrent.duration.{FiniteDuration, _}

sealed abstract class HmacAuthError(val message: String) extends Exception(message)
object HmacAuthError {
  case object NoAuthHeader     extends HmacAuthError("Could not find an Authorization header")
  case object NoDatetimeHeader extends HmacAuthError("Could not find an X-Datetime header")
  case object BadMAC           extends HmacAuthError("Bad MAC")
  case object InvalidMacFormat extends HmacAuthError("The MAC is not a valid Base64 string")
  case object InvalidDatetime  extends HmacAuthError("The datetime is not a valid UTC datetime string")
  case object Timeout          extends HmacAuthError("The request time window is closed")
}

object HmacAuthMiddleware {
  val defaultDuration: FiniteDuration = 5.minutes

  private def verifyFromHeader[F[_]](
      req: Request[F],
      key: MacSigningKey[HMACSHA256],
      duration: FiniteDuration
  ): Either[HmacAuthError, Unit] =
    for {
      authHeader <- req.headers
        .get(Authorization)
        .flatMap { t =>
          t.credentials match {
            case Credentials.Token(scheme, token) if scheme == AuthScheme.Bearer =>
              Some(token)
            case _ => None
          }
        }
        .toRight(HmacAuthError.NoAuthHeader)
      datetimeHeader <- req.headers
        .get(CaseInsensitiveString("X-Datetime"))
        .toRight(HmacAuthError.NoDatetimeHeader)
      instant <- HMAC.http.verifyFromHeader(
        req.method.name,
        req.uri.renderString,
        datetimeHeader.value,
        authHeader,
        key
      )
      _ <- Either.cond(
        Instant.now().isBefore(instant.plus(Duration.ofNanos(duration.toNanos))),
        (),
        HmacAuthError.Timeout
      )
    } yield ()

  def apply[F[_]: Sync](key: MacSigningKey[HMACSHA256], duration: FiniteDuration = defaultDuration)(routes: HttpRoutes[F]): HttpRoutes[F] =
    Kleisli { req: Request[F] =>
      verifyFromHeader(req, key, duration) match {
        case Left(error) => OptionT.some[F](Response[F](Status.Forbidden).withEntity(error.message))
        case Right(_)    => routes(req)
      }
    }
} 
Example 2
Source File: HmacAuthMiddlewareSpec.scala    From iotchain   with MIT License 5 votes vote down vote up
package jbok.network.http.server.middleware

import java.time.Instant

import cats.Id
import cats.effect.IO
import cats.implicits._
import jbok.common.CommonSpec
import jbok.network.http.server.authentication.HMAC
import org.http4s.dsl.io._
import org.http4s.headers.Authorization
import org.http4s.implicits._
import org.http4s.{AuthScheme, Credentials, Header, HttpRoutes, Request, Status, Uri}
import scodec.bits.ByteVector
import tsec.mac.jca.{HMACSHA256, MacSigningKey}

import scala.concurrent.duration._

class HmacAuthMiddlewareSpec extends CommonSpec {
  "HmacAuthMiddleware" should {
    val key = HMACSHA256.buildKey[Id](
      ByteVector.fromValidHex("70ea14ac30939a972b5a67cab952d6d7d474727b05fe7f9283abc1e505919e83").toArray
    )

    def sign(url: String): (String, String) = {
      val datetime  = Instant.now().toString
      val signature = HMAC.http.signForHeader("GET", url, datetime, key).unsafeRunSync()
      (signature, datetime)
    }

    val routes = HttpRoutes.of[IO] {
      case GET -> Root / "ping" => Ok("pong")
    }

    val service = routes.orNotFound
    val req     = Request[IO](uri = Uri.uri("/ping"))
    service.run(req).unsafeRunSync().status shouldBe Status.Ok
    val authedService = HmacAuthMiddleware(key)(routes).orNotFound

    "403 if no Authorization header" in {
      val resp = authedService.run(req).unsafeRunSync()
      val text = resp.bodyAsText.compile.foldMonoid.unsafeRunSync()
      resp.status shouldBe Status.Forbidden
      text shouldBe HmacAuthError.NoAuthHeader.message
    }

    "403 if no X-Datetime header" in {
      val signature = HMAC.http.signForHeader("GET", "/ping", Instant.now().toString, key).unsafeRunSync()
      val req =
        Request[IO](uri = Uri.uri("/ping")).putHeaders(Authorization(Credentials.Token(AuthScheme.Bearer, signature)))
      val resp = authedService.run(req).unsafeRunSync()
      val text = resp.bodyAsText.compile.foldMonoid.unsafeRunSync()
      resp.status shouldBe Status.Forbidden
      text shouldBe HmacAuthError.NoDatetimeHeader.message
    }

    "403 if time window is closed" in {
      val authedService = HmacAuthMiddleware(key, 2.seconds)(routes).orNotFound
      val now           = Instant.now()
      val signature     = HMAC.http.signForHeader("GET", "/ping", now.toString, key).unsafeRunSync()
      val req =
        Request[IO](uri = Uri.uri("/ping"))
          .putHeaders(
            Authorization(Credentials.Token(AuthScheme.Bearer, signature)),
            Header("X-Datetime", now.toString)
          )

      val resp = authedService.run(req).unsafeRunSync()
      resp.status shouldBe Status.Ok

      IO.sleep(3.seconds).unsafeRunSync()
      val resp2 = authedService.run(req).unsafeRunSync()
      val text  = resp2.bodyAsText.compile.foldMonoid.unsafeRunSync()
      resp2.status shouldBe Status.Forbidden
      text shouldBe HmacAuthError.Timeout.message
    }

    "helper" in {
      val (sig, date) = sign("/v1/blocks")
      println(("Authorization", s"Bearer $sig"))
      println(("X-Datetime", date))
      println(("Random key", ByteVector(MacSigningKey.toJavaKey[HMACSHA256](HMACSHA256.generateKey[Id]).getEncoded).toHex))
    }
  }
} 
Example 3
Source File: BearerTokenAuthenticatorTests.scala    From tsec   with MIT License 5 votes vote down vote up
package tsec.authentication

import java.time.Instant

import cats.effect.IO
import org.http4s.headers.Authorization
import org.http4s.{AuthScheme, Credentials, Request}
import tsec.common.SecureRandomId

import scala.concurrent.duration._

class BearerTokenAuthenticatorTests extends RequestAuthenticatorSpec {

  def timeoutAuthSpecTester: AuthSpecTester[TSecBearerToken[Int]] = {
    val tokenStore: BackingStore[IO, SecureRandomId, TSecBearerToken[Int]] =
      dummyBackingStore[IO, SecureRandomId, TSecBearerToken[Int]](s => SecureRandomId.coerce(s.id))
    val dummyStore    = dummyBackingStore[IO, Int, DummyUser](_.id)
    val settings      = TSecTokenSettings(10.minutes, Some(10.minutes))
    val authenticator = BearerTokenAuthenticator(tokenStore, dummyStore, settings)
    new AuthSpecTester[TSecBearerToken[Int]](authenticator, dummyStore) {
      def embedInRequest(request: Request[IO], authenticator: TSecBearerToken[Int]): Request[IO] =
        request.putHeaders(Authorization(Credentials.Token(AuthScheme.Bearer, authenticator.id)))

      def expireAuthenticator(b: TSecBearerToken[Int]): IO[TSecBearerToken[Int]] =
        authenticator.update(b.copy(expiry = Instant.now.minusSeconds(30)))

      def timeoutAuthenticator(b: TSecBearerToken[Int]): IO[TSecBearerToken[Int]] =
        authenticator.update(b.copy(lastTouched = Some(Instant.now.minusSeconds(300000))))

      def wrongKeyAuthenticator: IO[TSecBearerToken[Int]] =
        IO.pure(TSecBearerToken(SecureRandomId.Interactive.generate, -20, Instant.now(), None))
    }
  }

  AuthenticatorTest("Bearer token authenticator", timeoutAuthSpecTester)
  requestAuthTests[TSecBearerToken[Int]]("Bearer token Request handler", timeoutAuthSpecTester)

} 
Example 4
Source File: BasicAuthentication.scala    From endpoints4s   with MIT License 5 votes vote down vote up
package endpoints4s.http4s.client

import endpoints4s.{Tupler, algebra}
import endpoints4s.algebra.BasicAuthentication.Credentials
import endpoints4s.algebra.Documentation
import org.http4s.headers.Authorization
import org.http4s.BasicCredentials


trait BasicAuthentication extends algebra.BasicAuthentication {
  self: EndpointsWithCustomErrors =>

  private[endpoints4s] def authenticatedRequest[U, E, H, UE, HCred, Out](
      method: Method,
      url: Url[U],
      entity: RequestEntity[E],
      headers: RequestHeaders[H],
      requestDocs: Documentation
  )(implicit
      tuplerUE: Tupler.Aux[U, E, UE],
      tuplerHCred: Tupler.Aux[H, Credentials, HCred],
      tuplerUEHCred: Tupler.Aux[UE, HCred, Out]
  ): Request[Out] = {
    val basicAuthenticationHeader: RequestHeaders[Credentials] =
      (credentials, request) => {
        request.putHeaders(
          Authorization(
            BasicCredentials(credentials.username, credentials.password)
          )
        )
      }
    request(
      method,
      url,
      entity,
      requestDocs,
      headers ++ basicAuthenticationHeader
    )
  }

} 
Example 5
Source File: RestKeyMiddlewareSpec.scala    From pizza-auth-3   with MIT License 5 votes vote down vote up
package moe.pizza.auth.webapp.rest

import org.http4s._
import org.http4s.dsl._
import org.http4s.headers.Authorization
import org.http4s.util.Writer
import org.scalatest.{FlatSpec, MustMatchers}


class RestKeyMiddlewareSpec extends FlatSpec with MustMatchers {

  val emptyservice = HttpService {
    case req @ GET -> Root =>
      Ok("inner service")
  }

  val svc = new RestKeyMiddleware(List("key1", "key2")).apply(emptyservice)

  "when wrapping a service it" should "pass through calls with valid keys" in {
    val r = svc
      .apply(
        new Request(uri = Uri.uri("/"),
                    headers =
                      Headers(new Authorization(OAuth2BearerToken("key1")))))
      .run
    r.status must equal(Ok)
  }

  "when wrapping a service it" should "fail calls without valid keys" in {
    val r = svc
      .apply(
        new Request(uri = Uri.uri("/"),
                    headers =
                      Headers(new Authorization(OAuth2BearerToken("key3")))))
      .run
    r.status must equal(Unauthorized)
  }

} 
Example 6
Source File: KubeConfig.scala    From kubernetes-client   with Apache License 2.0 5 votes vote down vote up
package com.goyeau.kubernetes.client

import java.io.File

import cats.effect.Sync
import com.goyeau.kubernetes.client.util.Yamls
import io.chrisdavenport.log4cats.Logger
import org.http4s.Uri
import org.http4s.headers.Authorization

case class KubeConfig(
    server: Uri,
    authorization: Option[Authorization] = None,
    caCertData: Option[String] = None,
    caCertFile: Option[File] = None,
    clientCertData: Option[String] = None,
    clientCertFile: Option[File] = None,
    clientKeyData: Option[String] = None,
    clientKeyFile: Option[File] = None,
    clientKeyPass: Option[String] = None
) {
  require(caCertData.isEmpty || caCertFile.isEmpty, "caCertData and caCertFile can't be set at the same time")
  require(
    clientCertData.isEmpty || clientCertFile.isEmpty,
    "clientCertData and clientCertFile can't be set at the same time"
  )
}

object KubeConfig {

  @deprecated(message = "Use fromFile instead", since = "0.4.1")
  def apply[F[_]: Sync: Logger](kubeconfig: File): F[KubeConfig]    = fromFile(kubeconfig)
  def fromFile[F[_]: Sync: Logger](kubeconfig: File): F[KubeConfig] = Yamls.fromKubeConfigFile(kubeconfig, None)

  @deprecated(message = "Use fromFile instead", since = "0.4.1")
  def apply[F[_]: Sync: Logger](kubeconfig: File, contextName: String): F[KubeConfig] =
    fromFile(kubeconfig, contextName)
  def fromFile[F[_]: Sync: Logger](kubeconfig: File, contextName: String): F[KubeConfig] =
    Yamls.fromKubeConfigFile(kubeconfig, Option(contextName))
} 
Example 7
Source File: LoginTest.scala    From scala-pet-store   with Apache License 2.0 5 votes vote down vote up
package io.github.pauljamescleary.petstore
package infrastructure.endpoint

import cats.data.Kleisli
import cats.effect.IO
import domain.authentication.{LoginRequest, SignupRequest}
import domain.users.{Role, User}
import org.http4s.circe.{jsonEncoderOf, jsonOf}
import org.http4s.client.dsl.Http4sClientDsl
import org.http4s.{EntityDecoder, EntityEncoder, HttpApp, Request, Response}
import org.http4s.implicits._
import org.http4s.headers.Authorization
import io.circe.generic.auto._
import org.http4s.dsl.Http4sDsl

trait LoginTest extends Http4sClientDsl[IO] with Http4sDsl[IO] {
  implicit val userEnc: EntityEncoder[IO, User] = jsonEncoderOf
  implicit val userDec: EntityDecoder[IO, User] = jsonOf

  implicit val signUpRequestEnc: EntityEncoder[IO, SignupRequest] = jsonEncoderOf
  implicit val signUpRequestDec: EntityDecoder[IO, SignupRequest] = jsonOf

  implicit val loginRequestEnc: EntityEncoder[IO, LoginRequest] = jsonEncoderOf
  implicit val loginRequestDec: EntityDecoder[IO, LoginRequest] = jsonOf

  def signUpAndLogIn(
      userSignUp: SignupRequest,
      userEndpoint: HttpApp[IO],
  ): IO[(User, Option[Authorization])] =
    for {
      signUpRq <- POST(userSignUp, uri"/users")
      signUpResp <- userEndpoint.run(signUpRq)
      user <- signUpResp.as[User]
      loginBody = LoginRequest(userSignUp.userName, userSignUp.password)
      loginRq <- POST(loginBody, uri"/users/login")
      loginResp <- userEndpoint.run(loginRq)
    } yield {
      user -> loginResp.headers.get(Authorization)
    }

  def signUpAndLogInAsAdmin(
      userSignUp: SignupRequest,
      userEndpoint: Kleisli[IO, Request[IO], Response[IO]],
  ): IO[(User, Option[Authorization])] =
    signUpAndLogIn(userSignUp.copy(role = Role.Admin), userEndpoint)

  def signUpAndLogInAsCustomer(
      userSignUp: SignupRequest,
      userEndpoint: Kleisli[IO, Request[IO], Response[IO]],
  ): IO[(User, Option[Authorization])] =
    signUpAndLogIn(userSignUp.copy(role = Role.Customer), userEndpoint)
} 
Example 8
Source File: JwtTokenAuthMiddleware.scala    From core   with Apache License 2.0 5 votes vote down vote up
package com.smartbackpackerapp.http.auth

import cats.data.{EitherT, Kleisli, OptionT}
import cats.effect.Sync
import cats.syntax.applicativeError._
import cats.syntax.functor._
import com.smartbackpackerapp.http.auth.JwtTokenAuthMiddleware.AuthConfig
import org.http4s.Credentials.Token
import org.http4s.dsl.Http4sDsl
import org.http4s.{AuthScheme, AuthedService, Request}
import org.http4s.headers.Authorization
import org.http4s.server.AuthMiddleware
import tsec.jws.mac.JWTMac
import tsec.mac.imports._

object JwtTokenAuthMiddleware {
  def apply[F[_] : Sync](apiToken: Option[String]): F[AuthMiddleware[F, String]] =
    new Middleware[F](apiToken).middleware

  case class AuthConfig(jwtKey: MacSigningKey[HMACSHA256])
}

class Middleware[F[_]](apiToken: Option[String])(implicit F: Sync[F]) {

  private val ifEmpty = F.raiseError[AuthMiddleware[F, String]](new Exception("Api Token not found"))

  private def generateJwtKey(token: String): F[MacSigningKey[HMACSHA256]] = {
    F.catchNonFatal(HMACSHA256.buildKeyUnsafe(token.getBytes))
  }

  val middleware: F[AuthMiddleware[F, String]] = apiToken.fold(ifEmpty) { token =>
    generateJwtKey(token).map { jwtKey =>
      val config = AuthConfig(jwtKey)
      new JwtTokenAuthMiddleware[F](config).middleware
    }
  }
}

class JwtTokenAuthMiddleware[F[_] : Sync](config: AuthConfig) extends Http4sDsl[F] {

  private val onFailure: AuthedService[String, F] =
    Kleisli(req => OptionT.liftF(Forbidden(req.authInfo)))

  private def bearerTokenFromRequest(request: Request[F]): OptionT[F, String] =
    OptionT.fromOption[F] {
      request.headers.get(Authorization).collect {
        case Authorization(Token(AuthScheme.Bearer, token)) => token
      }
    }

  private def verifyToken(request: Request[F],
                          jwtKey: MacSigningKey[HMACSHA256]): OptionT[F, String] =
    for {
      token       <- bearerTokenFromRequest(request)
      verified    <- OptionT.liftF(JWTMac.verifyAndParse[F, HMACSHA256](token, jwtKey))
      accessToken <- OptionT.fromOption[F](verified.body.subject)
    } yield accessToken

  private def authUser(jwtKey: MacSigningKey[HMACSHA256]): Kleisli[F, Request[F], Either[String, String]] =
    Kleisli { request =>
      verifyToken(request, jwtKey).value.map { option =>
        Either.cond[String, String](option.isDefined, option.get, "Unable to authorize token")
      }.recoverWith {
        case MacVerificationError(msg) => EitherT.leftT(msg).value
      }
    }

  def middleware: AuthMiddleware[F, String] =
    AuthMiddleware(authUser(config.jwtKey), onFailure)

}