next.proxy.request.scala Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of otoroshi_2.12 Show documentation
Show all versions of otoroshi_2.12 Show documentation
Lightweight api management on top of a modern http reverse proxy
The newest version!
package otoroshi.next.proxy
import akka.http.scaladsl.model.Uri
import akka.stream.scaladsl.Source
import akka.util.ByteString
import com.auth0.jwt.JWT
import com.auth0.jwt.algorithms.Algorithm
import com.google.common.base.Charsets
import otoroshi.env.Env
import otoroshi.models.{ApiKey, BackOfficeUser, HSAlgoSettings, SecComInfoTokenVersion}
import otoroshi.utils.http.RequestImplicits.EnhancedRequestHeader
import otoroshi.utils.infotoken.InfoTokenHelper
import otoroshi.utils.syntax.implicits.BetterSyntax
import play.api.libs.json.Json
import play.api.libs.typedmap.TypedMap
import play.api.mvc.{Cookies, Headers, Request}
import play.api.mvc.request.{Cell, RemoteConnection, RequestAttrKey, RequestTarget}
import java.net.{InetAddress, URI, URLEncoder}
import java.security.cert.X509Certificate
import java.util.Base64
import scala.concurrent.duration.DurationInt
class RelayRoutingRequest(req: Request[Source[ByteString, _]], cookies: Cookies, certs: Option[Seq[X509Certificate]])
extends Request[Source[ByteString, _]] {
lazy val version = req.version
lazy val reqId = req.headers.get("Otoroshi-Relay-Routing-Id").get.toLong
lazy val method = req.headers.get("Otoroshi-Relay-Routing-Method").get
lazy val body = req.body
lazy val _remoteAddr = req.headers.get("Otoroshi-Relay-Routing-Remote-Addr").get
lazy val _remoteAddrInet = InetAddress.getByName(_remoteAddr)
lazy val _remoteSecured = req.headers.get("Otoroshi-Relay-Routing-Secured").get.toBoolean
lazy val _remoteHasBody = req.headers.get("Otoroshi-Relay-Routing-Has-Body").get.toBoolean
lazy val _remoteUriStr = req.headers.get("Otoroshi-Relay-Routing-Uri").get
lazy val attrs = TypedMap.apply(
RequestAttrKey.Id -> reqId,
RequestAttrKey.Cookies -> Cell(cookies)
)
lazy val headers: Headers = Headers(
req.headers.toSimpleMap.toSeq
.filterNot(_._1 == "Otoroshi-Relay-Routing-Cookies")
.filter(_._1.startsWith("Otoroshi-Relay-Routing-Header-"))
.map(v => (v._1.replace("Otoroshi-Relay-Routing-Header-", ""), v._2)): _*
)
lazy val connection: RemoteConnection = new RelayRoutingRemoteConnection(_remoteAddrInet, _remoteSecured, certs)
lazy val target: RequestTarget = new RelayRoutingRequestTarget(_remoteUriStr)
}
class TunnelRequest(
requestId: Long,
val version: String,
val method: String,
val body: Source[ByteString, _],
_remoteUriStr: String,
_remoteAddr: String,
_remoteSecured: Boolean,
_remoteHasBody: Boolean,
_headers: Map[String, String],
cookies: Cookies,
certs: Option[Seq[X509Certificate]]
) extends Request[Source[ByteString, _]] {
lazy val _remoteUri = Uri(_remoteUriStr)
lazy val _remoteAddrInet = InetAddress.getByName(_remoteAddr)
lazy val attrs = TypedMap.apply(
RequestAttrKey.Id -> requestId,
RequestAttrKey.Cookies -> Cell(cookies)
)
lazy val headers: Headers = Headers(_headers.toSeq: _*)
lazy val connection: RemoteConnection = new RelayRoutingRemoteConnection(_remoteAddrInet, _remoteSecured, certs)
lazy val target: RequestTarget = new RelayRoutingRequestTarget(_remoteUriStr)
}
class RelayRoutingRemoteConnection(
_remoteAddrInet: InetAddress,
_remoteSecured: Boolean,
certs: Option[Seq[X509Certificate]]
) extends RemoteConnection {
override def remoteAddress: InetAddress = _remoteAddrInet
override def secure: Boolean = _remoteSecured
override def clientCertificateChain: Option[Seq[X509Certificate]] = certs
}
class RelayRoutingRequestTarget(_remoteUriStr: String) extends RequestTarget {
private lazy val _remoteUri = Uri(_remoteUriStr)
private lazy val _remoteURI = URI.create(_remoteUriStr)
override def uri: URI = _remoteURI
override def uriString: String = _remoteUriStr
override def path: String = _remoteUri.path.toString()
override def queryMap: Map[String, Seq[String]] = _remoteUri.query().toMultiMap
}
class BackOfficeRequest(
request: Request[Source[ByteString, _]],
host: String,
apikey: ApiKey,
user: BackOfficeUser,
env: Env
) extends Request[Source[ByteString, _]] {
private val newUri = {
val path = request.path.replaceFirst("/bo/api/proxy/", "/").replace("//", "/")
request.queryString match {
case map if map.nonEmpty =>
val queryString = map.flatMap(t => t._2.map(v => s"${t._1}=${URLEncoder.encode(v, "UTF-8")}")).mkString("&")
s"${path}?${queryString}"
case map => path
}
}
val otoClaim = InfoTokenHelper
.generateInfoToken(
name = "Backoffice",
secComInfoTokenVersion = SecComInfoTokenVersion.Latest,
secComTtl = 30.seconds,
apiKey = apikey.some,
paUsr = None,
requestHeader = request.some,
issuer = None,
sub = None,
addFields = None
)(env)
.serialize(HSAlgoSettings(256, env.sharedKey))(env)
private val addHeaders = Seq(
env.Headers.OtoroshiClaim -> otoClaim,
"Host" -> host,
"X-Forwarded-For" -> request.theIpAddress(env),
env.Headers.OtoroshiVizFromLabel -> "Otoroshi Admin UI",
env.Headers.OtoroshiVizFrom -> "otoroshi-admin-ui",
env.Headers.OtoroshiClientId -> apikey.clientId,
env.Headers.OtoroshiClientSecret -> apikey.clientSecret,
env.Headers.OtoroshiAdminProfile -> Base64.getUrlEncoder.encodeToString(
Json.stringify(user.profile).getBytes(Charsets.UTF_8)
),
"Otoroshi-Tenant" -> request.headers.get("Otoroshi-Tenant").getOrElse("default"),
"Otoroshi-BackOffice-User" -> JWT
.create()
.withClaim("user", Json.stringify(user.toJson))
.sign(Algorithm.HMAC512(apikey.clientSecret))
)
override def connection: RemoteConnection = new BackOfficeRemoteConnection(request)
override def target: RequestTarget = new BackOfficeRequestTarget(newUri)
override def headers: Headers = Headers.apply(((request.headers.headers.toMap ++ addHeaders.toMap).toSeq): _*)
override def version: String = request.version
override def attrs: TypedMap = request.attrs
override def method: String = request.method
override def body: Source[ByteString, _] = request.body
}
class BackOfficeRequestTarget(newUri: String) extends RequestTarget {
private val _uri = Uri(newUri)
override def uri: URI = URI.create(newUri)
override def uriString: String = _uri.toString()
override def path: String = _uri.path.toString()
override def queryMap: Map[String, Seq[String]] = _uri.query().toMultiMap
}
class BackOfficeRemoteConnection(request: Request[Source[ByteString, _]]) extends RemoteConnection {
override def remoteAddress: InetAddress = InetAddress.getLocalHost
override def clientCertificateChain: Option[Seq[X509Certificate]] = request.clientCertificateChain
override def secure: Boolean = request.secure
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy