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

pl.touk.nussknacker.restmodel.BaseEndpointDefinitions.scala Maven / Gradle / Ivy

There is a newer version: 1.18.1
Show newest version
package pl.touk.nussknacker.restmodel

import pl.touk.nussknacker.restmodel.BaseEndpointDefinitions.ToSecure
import pl.touk.nussknacker.security.AuthCredentials
import sttp.model.StatusCode.{Forbidden, Unauthorized}
import sttp.tapir.EndpointIO.Example
import sttp.tapir._

import scala.language.implicitConversions

trait BaseEndpointDefinitions {

  val baseNuApiEndpoint: PublicEndpoint[Unit, Unit, Unit, Any] = endpoint.in("api")

  implicit def toSecuredEndpoint[INPUT, BUSINESS_ERROR, OUTPUT, R](
      endpoint: Endpoint[Unit, INPUT, BUSINESS_ERROR, OUTPUT, R]
  ): ToSecure[INPUT, BUSINESS_ERROR, OUTPUT, R] =
    new ToSecure(endpoint)

}

object BaseEndpointDefinitions {

  type EndpointError[ERROR] = Either[SecurityError, ERROR]
  type SecuredEndpoint[INPUT, BUSINESS_ERROR, OUTPUT, -R] =
    Endpoint[AuthCredentials, INPUT, Either[BUSINESS_ERROR, SecurityError], OUTPUT, R]

  implicit class ToSecure[INPUT, BUSINESS_ERROR, OUTPUT, -R](
      val endpoint: PublicEndpoint[INPUT, BUSINESS_ERROR, OUTPUT, R]
  ) extends AnyVal {

    import Codecs._

    def withSecurity(auth: EndpointInput[AuthCredentials]): SecuredEndpoint[INPUT, BUSINESS_ERROR, OUTPUT, R] = {
      endpoint
        .securityIn(auth)
        .errorOutEither(
          oneOf(
            oneOfVariantFromMatchType(
              Unauthorized,
              plainBody[SecurityError.AuthenticationError.type]
                .example(
                  Example.of(
                    summary = Some("Authentication failed"),
                    value = SecurityError.AuthenticationError
                  )
                )
            ),
            oneOfVariantFromMatchType(
              Forbidden,
              plainBody[SecurityError.AuthorizationError.type]
                .example(
                  Example.of(
                    summary = Some("Authorization failed"),
                    value = SecurityError.AuthorizationError
                  )
                )
            )
          )
        )
    }

  }

  private object Codecs {

    implicit val authenticationErrorCodec
        : Codec[String, SecurityError.AuthenticationError.type, CodecFormat.TextPlain] = {
      Codec.string.map(
        Mapping.from[String, SecurityError.AuthenticationError.type](_ => SecurityError.AuthenticationError)(_ =>
          "The supplied authentication is invalid"
        )
      )
    }

    implicit val authorizationErrorCodec
        : Codec[String, SecurityError.AuthorizationError.type, CodecFormat.TextPlain] = {
      Codec.string.map(
        Mapping.from[String, SecurityError.AuthorizationError.type](_ => SecurityError.AuthorizationError)(_ =>
          "The supplied authentication is not authorized to access this resource"
        )
      )
    }

  }

}

sealed trait SecurityError

object SecurityError {
  case object AuthenticationError extends SecurityError
  case object AuthorizationError  extends SecurityError
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy