From 0c29638ce93450c9ece6daf57e0faee0d0982fc2 Mon Sep 17 00:00:00 2001 From: Mathieu Ancelin Date: Mon, 24 Jul 2023 15:14:21 +0200 Subject: [PATCH] fix callback without relay state for #1671 --- otoroshi/app/auth/oauth1.scala | 2 +- otoroshi/app/auth/saml/SAMLClient.scala | 10 +++- .../app/controllers/Auth0Controller.scala | 56 ++++++++++++------- 3 files changed, 45 insertions(+), 23 deletions(-) diff --git a/otoroshi/app/auth/oauth1.scala b/otoroshi/app/auth/oauth1.scala index e732532564..b63ef4464b 100644 --- a/otoroshi/app/auth/oauth1.scala +++ b/otoroshi/app/auth/oauth1.scala @@ -326,7 +326,7 @@ case class Oauth1AuthModule(authConfig: Oauth1ModuleConfig) extends AuthModule { if (parameters("oauth_callback_confirmed") == "true") { val redirect = request.getQueryString("redirect") - val hash = env.sign(s"${authConfig.id}:::backoffice") + val hash = env.sign(s"${authConfig.id}:::${descriptor.id}") val oauth_token = parameters("oauth_token") Redirect(s"${authConfig.authorizeURL}?oauth_token=$oauth_token&perms=read") .addingToSession( diff --git a/otoroshi/app/auth/saml/SAMLClient.scala b/otoroshi/app/auth/saml/SAMLClient.scala index 6df0e4a344..5358fc9d29 100644 --- a/otoroshi/app/auth/saml/SAMLClient.scala +++ b/otoroshi/app/auth/saml/SAMLClient.scala @@ -79,7 +79,7 @@ case class SAMLModule(authConfig: SamlAuthModuleConfig) extends AuthModule { implicit val req: RequestHeader = request val redirect = request.getQueryString("redirect") - val hash = env.sign(s"${authConfig.id}:::backoffice") + val hash = env.sign(s"${authConfig.id}:::${descriptor.id}") val relayState = URLEncoder.encode( s"hash=$hash&desc=${descriptor.id}&redirect_uri=${redirect.getOrElse( routes.PrivateAppsController.home.absoluteURL(env.exposedRootSchemeIsHttps) @@ -98,7 +98,13 @@ case class SAMLModule(authConfig: SamlAuthModuleConfig) extends AuthModule { } else { s"${authConfig.singleSignOnUrl}?SAMLRequest=${URLEncoder.encode(encoded, "UTF-8")}&RelayState=$relayState" } - Redirect(redirectUrl).addingToSession("hash" -> env.sign(s"${authConfig.id}:::backoffice")) + Redirect(redirectUrl) + .addingToSession( + "hash" -> env.sign(s"${authConfig.id}:::${descriptor.id}"), + "desc" -> descriptor.id, + "ref" -> authConfig.id, + "route" -> s"$isRoute", + ) } } } diff --git a/otoroshi/app/controllers/Auth0Controller.scala b/otoroshi/app/controllers/Auth0Controller.scala index 938b4c8976..4698009e5f 100644 --- a/otoroshi/app/controllers/Auth0Controller.scala +++ b/otoroshi/app/controllers/Auth0Controller.scala @@ -14,7 +14,7 @@ import otoroshi.security.IdGenerator import otoroshi.utils.{RegexPool, TypedMap} import otoroshi.utils.syntax.implicits._ import play.api.Logger -import play.api.libs.json.{JsArray, JsError, JsObject, JsSuccess, JsValue, Json} +import play.api.libs.json.{JsArray, JsError, JsNull, JsObject, JsString, JsSuccess, JsValue, Json} import play.api.mvc._ import java.net.URLEncoder @@ -700,36 +700,52 @@ class AuthController( } } - ((desc, ctx.request.getQueryString("state")) match { - case (Some(serviceId), _) if !isRoute => processService(serviceId) - case (Some(routeId), _) if isRoute => processRoute(routeId) + val stt = ctx.request.getQueryString("state") + // val bod: Map[String, Seq[String]] = ctx.request.body.asFormUrlEncoded.getOrElse(Map.empty[String, Seq[String]]) + // val context = Json.obj( + // "desc" -> desc.map(JsString.apply).getOrElse(JsNull).as[JsValue], + // "isRoute" -> isRoute, + // "refFromRelayState" -> refFromRelayState.map(JsString.apply).getOrElse(JsNull).as[JsValue], + // "state" -> stt.map(JsString.apply).getOrElse(JsNull).as[JsValue], + // "request" -> Json.obj( + // "query" -> req.queryString, + // "headers" -> req.headers.toMap, + // "session" -> req.session.data, + // "body" -> bod, + // ) + // ) + // logger.info(s"confidentialAppCallback context: ${context.prettify}") + + ((desc, stt) match { + case (Some(serviceId), _) if !isRoute => processService(serviceId).map(_.removingFromSession("desc", "ref", "route")) + case (Some(routeId), _) if isRoute => processRoute(routeId).map(_.removingFromSession("desc", "ref", "route")) case (_, Some(state)) => if (logger.isDebugEnabled) logger.debug(s"Received state : $state") val unsignedState = decryptState(ctx.request.requestHeader) (unsignedState \ "descriptor").asOpt[String] match { - case Some(route) if isRoute => processRoute(route) - case Some(service) if !isRoute => processService(service) + case Some(route) if isRoute => processRoute(route).map(_.removingFromSession("desc", "ref", "route")) + case Some(service) if !isRoute => processService(service).map(_.removingFromSession("desc", "ref", "route")) case _ => NotFound(otoroshi.views.html.oto.error(s"${if (isRoute) "Route" else "service"} not found", env)).vfuture } case (_, _) => NotFound(otoroshi.views.html.oto.error(s"${if (isRoute) "Route" else "service"} not found", env)).vfuture }) - .recover { - case t: Throwable => { - val errorId = IdGenerator.uuid - logger.error(s"An error occurred during the authentication callback with error id: '${errorId}'", t) - InternalServerError( - otoroshi.views.html.oto - .error( - message = - s"An error occurred during the authentication callback. Please contact your administrator with error id: ${errorId}", - _env = env, - title = "Authorization error" - ) - ) - } + .recover { + case t: Throwable => { + val errorId = IdGenerator.uuid + logger.error(s"An error occurred during the authentication callback with error id: '${errorId}'", t) + InternalServerError( + otoroshi.views.html.oto + .error( + message = + s"An error occurred during the authentication callback. Please contact your administrator with error id: ${errorId}", + _env = env, + title = "Authorization error" + ) + ) } + } } def auth0error(error: Option[String], error_description: Option[String]) =