Skip to content

Commit

Permalink
fix #1663
Browse files Browse the repository at this point in the history
  • Loading branch information
mathieuancelin committed Jul 17, 2023
1 parent 40c7b88 commit 2fe3d14
Show file tree
Hide file tree
Showing 9 changed files with 15,777 additions and 4,051 deletions.
3,725 changes: 2,903 additions & 822 deletions kubernetes/helm/otoroshi/crds-with-schema.yaml

Large diffs are not rendered by default.

8 changes: 7 additions & 1 deletion manual/src/main/paradox/code/openapi.json
Original file line number Diff line number Diff line change
Expand Up @@ -21631,7 +21631,13 @@
"description" : "???"
},
"singleLogoutUrl" : {
"type" : "string",
"oneOf" : [ {
"type" : "string",
"nullable" : true,
"description" : "null type"
}, {
"type" : "string"
} ],
"description" : "???"
},
"id" : {
Expand Down
64 changes: 34 additions & 30 deletions otoroshi/app/auth/saml/SAMLClient.scala
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,7 @@ import org.opensaml.security.x509.BasicX509Credential
import org.opensaml.xmlsec.SignatureSigningParameters
import org.opensaml.xmlsec.encryption.support.InlineEncryptedKeyResolver
import org.opensaml.xmlsec.keyinfo.KeyInfoCredentialResolver
import org.opensaml.xmlsec.keyinfo.impl.{
ChainingKeyInfoCredentialResolver,
StaticKeyInfoCredentialResolver,
X509KeyInfoGeneratorFactory
}
import org.opensaml.xmlsec.keyinfo.impl.{ChainingKeyInfoCredentialResolver, StaticKeyInfoCredentialResolver, X509KeyInfoGeneratorFactory}
import org.opensaml.xmlsec.signature.Signature
import org.opensaml.xmlsec.signature.impl.SignatureBuilder
import org.opensaml.xmlsec.signature.support.{SignatureConstants, SignatureException, SignatureSupport}
Expand All @@ -39,9 +35,9 @@ import otoroshi.ssl.{DynamicSSLEngineProvider, PemHeaders}
import otoroshi.utils.JsonPathValidator
import otoroshi.utils.syntax.implicits._
import play.api.Logger
import play.api.libs.json.{Format, JsArray, JsError, JsObject, JsString, JsSuccess, JsValue, Json}
import play.api.libs.json.{Format, JsArray, JsError, JsNull, JsObject, JsString, JsSuccess, JsValue, Json}
import play.api.mvc.Results.{BadRequest, Ok, Redirect}
import play.api.mvc.{AnyContent, Request, RequestHeader, Result}
import play.api.mvc.{AnyContent, Request, RequestHeader, Result, Results}
import play.twirl.api.TwirlHelperImports.twirlJavaCollectionToScala

import java.io.{ByteArrayInputStream, InputStreamReader, Reader, StringWriter, Writer}
Expand Down Expand Up @@ -106,15 +102,19 @@ case class SAMLModule(authConfig: SamlAuthModuleConfig) extends AuthModule {
)(implicit ec: ExecutionContext, env: Env): Future[Either[Result, Option[String]]] = {
getLogoutRequest(env, authConfig, user.map(_.metadata.getOrElse("saml-id", ""))).map {
case Left(_) => Right(None)
case Right(encoded) =>
if (authConfig.singleLogoutProtocolBinding == SAMLProtocolBinding.Post)
Left(Ok(otoroshi.views.html.oto.saml(encoded, authConfig.singleLogoutUrl, env)))
else {
env.Ws
.url(s"${authConfig.singleLogoutUrl}?SAMLRequest=${URLEncoder.encode(encoded, "UTF-8")}")
.get()
Right(None)
case Right(encoded) => authConfig.singleLogoutUrl match {
case None => Left(Results.InternalServerError(Json.obj("error" -> "no logout url configured !")))
case Some(singleLogoutUrl) => {
if (authConfig.singleLogoutProtocolBinding == SAMLProtocolBinding.Post)
Left(Ok(otoroshi.views.html.oto.saml(encoded, singleLogoutUrl, env)))
else {
env.Ws
.url(s"${singleLogoutUrl}?SAMLRequest=${URLEncoder.encode(encoded, "UTF-8")}")
.get()
Right(None)
}
}
}
}
}

Expand Down Expand Up @@ -209,15 +209,19 @@ case class SAMLModule(authConfig: SamlAuthModuleConfig) extends AuthModule {

getLogoutRequest(env, authConfig, Some(user.metadata.getOrElse("saml-id", ""))).map {
case Left(_) => Right(None)
case Right(encoded) =>
if (authConfig.singleLogoutProtocolBinding == SAMLProtocolBinding.Post)
Left(Ok(otoroshi.views.html.oto.saml(encoded, authConfig.singleLogoutUrl, env)))
else {
env.Ws
.url(s"${authConfig.singleLogoutUrl}?SAMLRequest=${URLEncoder.encode(encoded, "UTF-8")}")
.get()
Right(None)
case Right(encoded) => authConfig.singleLogoutUrl match {
case None => Left(Results.InternalServerError(Json.obj("error" -> "no logout url configured !")))
case Some(singleLogoutUrl) => {
if (authConfig.singleLogoutProtocolBinding == SAMLProtocolBinding.Post)
Left(Ok(otoroshi.views.html.oto.saml(encoded, singleLogoutUrl, env)))
else {
env.Ws
.url(s"${singleLogoutUrl}?SAMLRequest=${URLEncoder.encode(encoded, "UTF-8")}")
.get()
Right(None)
}
}
}
}
}

Expand Down Expand Up @@ -319,7 +323,7 @@ object SamlAuthModuleConfig extends FromJson[AuthModuleConfig] {
desc = (json \ "desc").asOpt[String].getOrElse("--"),
sessionMaxAge = (json \ "sessionMaxAge").asOpt[Int].getOrElse(86400),
singleSignOnUrl = (json \ "singleSignOnUrl").as[String],
singleLogoutUrl = (json \ "singleLogoutUrl").as[String],
singleLogoutUrl = (json \ "singleLogoutUrl").asOpt[String].filter(_.nonEmpty),
credentials = (json \ "credentials").as[SAMLCredentials](SAMLCredentials.fmt),
tags = (json \ "tags").asOpt[Seq[String]].getOrElse(Seq.empty[String]),
metadata = (json \ "metadata").asOpt[Map[String, String]].getOrElse(Map.empty),
Expand Down Expand Up @@ -401,16 +405,16 @@ object SamlAuthModuleConfig extends FromJson[AuthModuleConfig] {
else {
if (idpssoDescriptor.getSingleSignOnServices.isEmpty)
Left("Cannot find SSO binding in metadata")
else if (idpssoDescriptor.getSingleLogoutServices.isEmpty)
Left("Cannot find Single Logout Service in metadata")
// else if (idpssoDescriptor.getSingleLogoutServices.isEmpty)
// Left("Cannot find Single Logout Service in metadata")
else {
Right(
SamlAuthModuleConfig(
id = IdGenerator.token,
name = "SAML Module",
desc = "SAML Module",
singleSignOnUrl = idpssoDescriptor.getSingleSignOnServices.get(0).getLocation,
singleLogoutUrl = idpssoDescriptor.getSingleLogoutServices.get(0).getLocation,
singleLogoutUrl = Try(idpssoDescriptor.getSingleLogoutServices.get(0).getLocation).filter(_ != null).toOption,
issuer = entityDescriptor.getEntityID,
ssoProtocolBinding = SAMLProtocolBinding(idpssoDescriptor.getSingleSignOnServices.get(0).getBinding),
singleLogoutProtocolBinding =
Expand Down Expand Up @@ -669,7 +673,7 @@ case class SamlAuthModuleConfig(
sessionMaxAge: Int = 86400,
userValidators: Seq[JsonPathValidator] = Seq.empty,
singleSignOnUrl: String,
singleLogoutUrl: String,
singleLogoutUrl: Option[String],
ssoProtocolBinding: SAMLProtocolBinding = SAMLProtocolBinding.Redirect,
singleLogoutProtocolBinding: SAMLProtocolBinding = SAMLProtocolBinding.Redirect,
credentials: SAMLCredentials = SAMLCredentials(Credential(), Credential()),
Expand Down Expand Up @@ -711,7 +715,7 @@ case class SamlAuthModuleConfig(
"clientSideSessionEnabled" -> this.clientSideSessionEnabled,
"userValidators" -> JsArray(userValidators.map(_.json)),
"singleSignOnUrl" -> this.singleSignOnUrl,
"singleLogoutUrl" -> this.singleLogoutUrl,
"singleLogoutUrl" -> this.singleLogoutUrl.map(JsString.apply).getOrElse(JsNull).asValue,
"credentials" -> SAMLCredentials.fmt.writes(this.credentials),
"tags" -> JsArray(tags.map(JsString.apply)),
"metadata" -> this.metadata,
Expand Down Expand Up @@ -748,7 +752,7 @@ object SAMLModule {
tags = Seq.empty,
metadata = Map.empty,
singleSignOnUrl = "",
singleLogoutUrl = "",
singleLogoutUrl = None,
issuer = "",
sessionCookieValues = SessionCookieValues(),
clientSideSessionEnabled = true
Expand Down
61 changes: 29 additions & 32 deletions otoroshi/app/controllers/BackOfficeController.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1061,43 +1061,40 @@ class BackOfficeController(
}

def fetchSAMLConfiguration() = BackOfficeActionAuth.async(parse.json) { ctx =>
{
import scala.xml.Elem
import scala.xml.XML._

Try {
val xmlContent: Either[String, Elem] = (ctx.request.body \ "url").asOpt[String] match {
case Some(url) => Right(load(url))
case None =>
(ctx.request.body \ "xml").asOpt[String] match {
case Some(content) => Right(loadString(content))
case None => Left("Missing body content")
}
}
import scala.xml.Elem
import scala.xml.XML._
Try {
val xmlContent: Either[String, Elem] = (ctx.request.body \ "url").asOpt[String] match {
case Some(url) => Right(load(url))
case None =>
(ctx.request.body \ "xml").asOpt[String] match {
case Some(content) => Right(loadString(content))
case None => Left("Missing body content")
}
}

xmlContent match {
case Left(err) => FastFuture.successful(BadRequest(err))
case Right(xmlContent) =>
var metadata = (xmlContent \\ "EntitiesDescriptor").toString
xmlContent match {
case Left(err) => FastFuture.successful(BadRequest(err))
case Right(xmlContent) =>
var metadata = (xmlContent \\ "EntitiesDescriptor").toString

if (metadata.isEmpty)
metadata = xmlContent.toString
if (metadata.isEmpty)
metadata = xmlContent.toString

SamlAuthModuleConfig.fromDescriptor(metadata) match {
case Left(err) => FastFuture.successful(BadRequest(err))
case Right(config) => FastFuture.successful(Ok(SamlAuthModuleConfig._fmt.writes(config)))
}
}
} recover { case e: Throwable =>
FastFuture.successful(
BadRequest(
Json.obj(
"error" -> e.getMessage
)
SamlAuthModuleConfig.fromDescriptor(metadata) match {
case Left(err) => FastFuture.successful(BadRequest(err))
case Right(config) => FastFuture.successful(Ok(SamlAuthModuleConfig._fmt.writes(config)))
}
}
} recover { case e: Throwable =>
FastFuture.successful(
BadRequest(
Json.obj(
"error" -> e.getMessage
)
)
} get
}
)
} get
}

def fetchBodiesFor(serviceId: String, requestId: String) =
Expand Down
28 changes: 17 additions & 11 deletions otoroshi/conf/schemas/openapi-cfg.json
Original file line number Diff line number Diff line change
Expand Up @@ -634,7 +634,7 @@
"entity_description.otoroshi.wasm.WasmDataRights": "???",
"entity_description.otoroshi.wasm.WasmSource": "???",
"entity_description.otoroshi.wasm.WasmSourceKind": "???",
"entity_description.otoroshi.wasm.WasmVmLifetime": "???",
"entity_description.otoroshi.wasm.WasmVmKillOptions": "???",
"entity_description.otoroshi.wasm.proxywasm.CorazaWafConfig": "???",
"operations.otoroshi.controllers.PrivateAppsController.registerSession_privateapps": "Registers a private app session",
"operations.otoroshi.controllers.PrivateAppsController.sendSelfUpdateLink_privateapps": "Send an email to a user to update its own settings",
Expand Down Expand Up @@ -2983,7 +2983,7 @@
"otoroshi.next.plugins.WasmAccessValidator.config": "???",
"otoroshi.next.plugins.WasmAccessValidator.functionName": "???",
"otoroshi.next.plugins.WasmAccessValidator.instances": "???",
"otoroshi.next.plugins.WasmAccessValidator.lifetime": "???",
"otoroshi.next.plugins.WasmAccessValidator.killOptions": "???",
"otoroshi.next.plugins.WasmAccessValidator.memoryPages": "???",
"otoroshi.next.plugins.WasmAccessValidator.opa": "???",
"otoroshi.next.plugins.WasmAccessValidator.source": "???",
Expand All @@ -2994,7 +2994,7 @@
"otoroshi.next.plugins.WasmBackend.config": "???",
"otoroshi.next.plugins.WasmBackend.functionName": "???",
"otoroshi.next.plugins.WasmBackend.instances": "???",
"otoroshi.next.plugins.WasmBackend.lifetime": "???",
"otoroshi.next.plugins.WasmBackend.killOptions": "???",
"otoroshi.next.plugins.WasmBackend.memoryPages": "???",
"otoroshi.next.plugins.WasmBackend.opa": "???",
"otoroshi.next.plugins.WasmBackend.source": "???",
Expand All @@ -3015,7 +3015,7 @@
"otoroshi.next.plugins.WasmOPA.config": "???",
"otoroshi.next.plugins.WasmOPA.functionName": "???",
"otoroshi.next.plugins.WasmOPA.instances": "???",
"otoroshi.next.plugins.WasmOPA.lifetime": "???",
"otoroshi.next.plugins.WasmOPA.killOptions": "???",
"otoroshi.next.plugins.WasmOPA.memoryPages": "???",
"otoroshi.next.plugins.WasmOPA.opa": "???",
"otoroshi.next.plugins.WasmOPA.source": "???",
Expand All @@ -3026,7 +3026,7 @@
"otoroshi.next.plugins.WasmPreRoute.config": "???",
"otoroshi.next.plugins.WasmPreRoute.functionName": "???",
"otoroshi.next.plugins.WasmPreRoute.instances": "???",
"otoroshi.next.plugins.WasmPreRoute.lifetime": "???",
"otoroshi.next.plugins.WasmPreRoute.killOptions": "???",
"otoroshi.next.plugins.WasmPreRoute.memoryPages": "???",
"otoroshi.next.plugins.WasmPreRoute.opa": "???",
"otoroshi.next.plugins.WasmPreRoute.source": "???",
Expand All @@ -3037,7 +3037,7 @@
"otoroshi.next.plugins.WasmRequestTransformer.config": "???",
"otoroshi.next.plugins.WasmRequestTransformer.functionName": "???",
"otoroshi.next.plugins.WasmRequestTransformer.instances": "???",
"otoroshi.next.plugins.WasmRequestTransformer.lifetime": "???",
"otoroshi.next.plugins.WasmRequestTransformer.killOptions": "???",
"otoroshi.next.plugins.WasmRequestTransformer.memoryPages": "???",
"otoroshi.next.plugins.WasmRequestTransformer.opa": "???",
"otoroshi.next.plugins.WasmRequestTransformer.source": "???",
Expand All @@ -3048,7 +3048,7 @@
"otoroshi.next.plugins.WasmResponseTransformer.config": "???",
"otoroshi.next.plugins.WasmResponseTransformer.functionName": "???",
"otoroshi.next.plugins.WasmResponseTransformer.instances": "???",
"otoroshi.next.plugins.WasmResponseTransformer.lifetime": "???",
"otoroshi.next.plugins.WasmResponseTransformer.killOptions": "???",
"otoroshi.next.plugins.WasmResponseTransformer.memoryPages": "???",
"otoroshi.next.plugins.WasmResponseTransformer.opa": "???",
"otoroshi.next.plugins.WasmResponseTransformer.source": "???",
Expand All @@ -3059,7 +3059,7 @@
"otoroshi.next.plugins.WasmRouteMatcher.config": "???",
"otoroshi.next.plugins.WasmRouteMatcher.functionName": "???",
"otoroshi.next.plugins.WasmRouteMatcher.instances": "???",
"otoroshi.next.plugins.WasmRouteMatcher.lifetime": "???",
"otoroshi.next.plugins.WasmRouteMatcher.killOptions": "???",
"otoroshi.next.plugins.WasmRouteMatcher.memoryPages": "???",
"otoroshi.next.plugins.WasmRouteMatcher.opa": "???",
"otoroshi.next.plugins.WasmRouteMatcher.source": "???",
Expand All @@ -3070,7 +3070,7 @@
"otoroshi.next.plugins.WasmRouter.config": "???",
"otoroshi.next.plugins.WasmRouter.functionName": "???",
"otoroshi.next.plugins.WasmRouter.instances": "???",
"otoroshi.next.plugins.WasmRouter.lifetime": "???",
"otoroshi.next.plugins.WasmRouter.killOptions": "???",
"otoroshi.next.plugins.WasmRouter.memoryPages": "???",
"otoroshi.next.plugins.WasmRouter.opa": "???",
"otoroshi.next.plugins.WasmRouter.source": "???",
Expand All @@ -3081,7 +3081,7 @@
"otoroshi.next.plugins.WasmSink.config": "???",
"otoroshi.next.plugins.WasmSink.functionName": "???",
"otoroshi.next.plugins.WasmSink.instances": "???",
"otoroshi.next.plugins.WasmSink.lifetime": "???",
"otoroshi.next.plugins.WasmSink.killOptions": "???",
"otoroshi.next.plugins.WasmSink.memoryPages": "???",
"otoroshi.next.plugins.WasmSink.opa": "???",
"otoroshi.next.plugins.WasmSink.source": "???",
Expand Down Expand Up @@ -3454,7 +3454,7 @@
"otoroshi.wasm.WasmConfig.config": "???",
"otoroshi.wasm.WasmConfig.functionName": "???",
"otoroshi.wasm.WasmConfig.instances": "???",
"otoroshi.wasm.WasmConfig.lifetime": "???",
"otoroshi.wasm.WasmConfig.killOptions": "???",
"otoroshi.wasm.WasmConfig.memoryPages": "???",
"otoroshi.wasm.WasmConfig.opa": "???",
"otoroshi.wasm.WasmConfig.source": "???",
Expand All @@ -3464,13 +3464,19 @@
"otoroshi.wasm.WasmSource.kind": "???",
"otoroshi.wasm.WasmSource.opts": "???",
"otoroshi.wasm.WasmSource.path": "???",
"otoroshi.wasm.WasmVmKillOptions.immortal": "???",
"otoroshi.wasm.WasmVmKillOptions.maxAvgCallDuration": "???",
"otoroshi.wasm.WasmVmKillOptions.maxCalls": "???",
"otoroshi.wasm.WasmVmKillOptions.maxMemoryUsage": "???",
"otoroshi.wasm.WasmVmKillOptions.maxUnusedDuration": "???",
"otoroshi.wasm.proxywasm.CorazaWafConfig.config": "???",
"otoroshi.wasm.proxywasm.CorazaWafConfig.description": "???",
"otoroshi.wasm.proxywasm.CorazaWafConfig.id": "???",
"otoroshi.wasm.proxywasm.CorazaWafConfig.inspectBody": "???",
"otoroshi.wasm.proxywasm.CorazaWafConfig.location": "???",
"otoroshi.wasm.proxywasm.CorazaWafConfig.metadata": "???",
"otoroshi.wasm.proxywasm.CorazaWafConfig.name": "???",
"otoroshi.wasm.proxywasm.CorazaWafConfig.poolCapacity": "???",
"otoroshi.wasm.proxywasm.CorazaWafConfig.tags": "???",
"tags.admin-sessions": "???",
"tags.admins": "???",
Expand Down
Loading

0 comments on commit 2fe3d14

Please sign in to comment.