From 369ca7abd6b67a68e184e6f0a14babcd6e8d90d2 Mon Sep 17 00:00:00 2001 From: Mathieu Ancelin Date: Fri, 20 Sep 2024 14:20:49 +0200 Subject: [PATCH] fix #1985 --- otoroshi/app/auth/basic.scala | 3 ++- otoroshi/app/auth/ldap.scala | 3 ++- otoroshi/app/models/apikey.scala | 15 ++++++++++----- otoroshi/app/next/plugins/apikey.scala | 3 ++- .../app/next/plugins/clientcredentials.scala | 12 ++++++------ otoroshi/app/plugins/apikeys.scala | 17 +++++++++-------- otoroshi/app/plugins/body.scala | 3 ++- otoroshi/app/plugins/core/apikeys.scala | 5 +++-- 8 files changed, 36 insertions(+), 25 deletions(-) diff --git a/otoroshi/app/auth/basic.scala b/otoroshi/app/auth/basic.scala index 6effd3b821..7c9ce54c8b 100644 --- a/otoroshi/app/auth/basic.scala +++ b/otoroshi/app/auth/basic.scala @@ -243,7 +243,8 @@ case class BasicAuthModule(authConfig: BasicAuthModuleConfig) extends AuthModule Option(base64) .map(decodeBase64) .map(_.split(":").toSeq) - .flatMap(a => a.headOption.flatMap(head => a.lastOption.map(last => (head, last)))) + .filter(v => v.nonEmpty && v.length > 1) + .flatMap(a => a.headOption.map(head => (head, a.tail.mkString(":")))) } diff --git a/otoroshi/app/auth/ldap.scala b/otoroshi/app/auth/ldap.scala index 965126a92c..44b29900f2 100644 --- a/otoroshi/app/auth/ldap.scala +++ b/otoroshi/app/auth/ldap.scala @@ -677,7 +677,8 @@ case class LdapAuthModule(authConfig: LdapAuthModuleConfig) extends AuthModule { Option(base64) .map(decodeBase64) .map(_.split(":").toSeq) - .flatMap(a => a.headOption.flatMap(head => a.lastOption.map(last => (head, last)))) + .filter(v => v.nonEmpty && v.length > 1) + .flatMap(a => a.headOption.map(head => (head, a.tail.mkString(":")))) } def bindUser(username: String, password: String, descriptor: ServiceDescriptor)(implicit diff --git a/otoroshi/app/models/apikey.scala b/otoroshi/app/models/apikey.scala index fececd0154..bd52f69c42 100644 --- a/otoroshi/app/models/apikey.scala +++ b/otoroshi/app/models/apikey.scala @@ -981,8 +981,9 @@ object ApiKeyHelper { } getOrElse FastFuture.successful(None) } else if (authBasic.isDefined && descriptor.apiKeyConstraints.basicAuth.enabled) { val auth = authBasic.get - val id = auth.split(":").headOption.map(_.trim) - val secret = auth.split(":").lastOption.map(_.trim) + val parts = auth.split(":") + val id = parts.headOption.map(_.trim) + val secret = if (parts.length > 1) parts.tail.mkString(":").trim.some else None (id, secret) match { case (Some(apiKeyClientId), Some(apiKeySecret)) => { env.datastores.apiKeyDataStore @@ -1574,8 +1575,9 @@ object ApiKeyHelper { } getOrElse errorResult(Unauthorized, s"Invalid ApiKey provided", "errors.invalid.api.key") } else if (authBasic.isDefined && descriptor.apiKeyConstraints.basicAuth.enabled) { val auth = authBasic.get - val id = auth.split(":").headOption.map(_.trim) - val secret = auth.split(":").lastOption.map(_.trim) + val parts = auth.split(":") + val id = parts.headOption.map(_.trim) + val secret = if (parts.length > 1) parts.tail.mkString(":").trim.some else None (id, secret) match { case (Some(apiKeyClientId), Some(apiKeySecret)) => { env.datastores.apiKeyDataStore @@ -1739,7 +1741,10 @@ object ApiKeyHelper { ) ) .map(_.split(":")) - .filter(_.size == 2) + .collect { + case arr if arr.length == 2 => arr + case arr if arr.length > 2 => Array(arr.head, arr.tail.mkString(":")) + } .map(parts => ApikeyTuple(parts.head, parts.lastOption, location = location.some, otoBearer = None)) val authByCustomHeaders: Option[ApikeyTuple] = req.headers .get( diff --git a/otoroshi/app/next/plugins/apikey.scala b/otoroshi/app/next/plugins/apikey.scala index 13c16e5858..ae93013b0b 100644 --- a/otoroshi/app/next/plugins/apikey.scala +++ b/otoroshi/app/next/plugins/apikey.scala @@ -680,7 +680,8 @@ class ApikeyAuthModule extends NgPreRouting { Option(base64) .map(decodeBase64) .map(_.split(":").toSeq) - .flatMap(a => a.headOption.flatMap(head => a.lastOption.map(last => (head, last)))) + .filter(v => v.nonEmpty && v.length > 1) + .flatMap(a => a.headOption.map(head => (head, a.tail.mkString(":")))) } def unauthorized(config: ApikeyAuthModuleConfig) = { diff --git a/otoroshi/app/next/plugins/clientcredentials.scala b/otoroshi/app/next/plugins/clientcredentials.scala index ecdaab8d96..329f099c2f 100644 --- a/otoroshi/app/next/plugins/clientcredentials.scala +++ b/otoroshi/app/next/plugins/clientcredentials.scala @@ -133,7 +133,7 @@ class NgClientCredentials extends NgRequestSink { .map(v => new String(v)) .filter(_.contains(":")) .map(_.split(":").toSeq) - .map(v => Map("client_id" -> v.head, "client_secret" -> v.last)) + .map(v => Map("client_id" -> v.head, "client_secret" -> v.tail.mkString(":"))) .getOrElse(Map.empty[String, String]) f(map) } @@ -151,7 +151,7 @@ class NgClientCredentials extends NgRequestSink { .map(v => new String(v)) .filter(_.contains(":")) .map(_.split(":").toSeq) - .map(v => Map("client_id" -> v.head, "client_secret" -> v.last)) + .map(v => Map("client_id" -> v.head, "client_secret" -> v.tail.mkString(":"))) .getOrElse(Map.empty[String, String]) f(map) } @@ -433,7 +433,7 @@ class NgClientCredentials extends NgRequestSink { .map(v => new String(v)) .filter(_.contains(":")) .map(_.split(":").toSeq) - .map(v => (v.head, v.last)) + .map(v => (v.head, v.tail.mkString(":"))) .map { case (clientId, clientSecret) => handleTokenRequest( ClientCredentialFlowBody( @@ -544,7 +544,7 @@ class NgClientCredentialTokenEndpoint extends NgBackendCall { .map(v => new String(v)) .filter(_.contains(":")) .map(_.split(":").toSeq) - .map(v => Map("client_id" -> v.head, "client_secret" -> v.last)) + .map(v => Map("client_id" -> v.head, "client_secret" -> v.tail.mkString(":"))) .getOrElse(Map.empty[String, String]) f(map) } @@ -562,7 +562,7 @@ class NgClientCredentialTokenEndpoint extends NgBackendCall { .map(v => new String(v)) .filter(_.contains(":")) .map(_.split(":").toSeq) - .map(v => Map("client_id" -> v.head, "client_secret" -> v.last)) + .map(v => Map("client_id" -> v.head, "client_secret" -> v.tail.mkString(":"))) .getOrElse(Map.empty[String, String]) f(map) } @@ -692,7 +692,7 @@ class NgClientCredentialTokenEndpoint extends NgBackendCall { .map(v => new String(v)) .filter(_.contains(":")) .map(_.split(":").toSeq) - .map(v => (v.head, v.last)) + .map(v => (v.head, v.tail.mkString(":"))) .map { case (clientId, clientSecret) => handleTokenRequest( NgClientCredentialTokenEndpointBody( diff --git a/otoroshi/app/plugins/apikeys.scala b/otoroshi/app/plugins/apikeys.scala index 3fd3440694..4f402f2ced 100644 --- a/otoroshi/app/plugins/apikeys.scala +++ b/otoroshi/app/plugins/apikeys.scala @@ -420,7 +420,7 @@ class ClientCredentialFlow extends RequestTransformer { .map(v => new String(v)) .filter(_.contains(":")) .map(_.split(":").toSeq) - .map(v => Map("client_id" -> v.head, "client_secret" -> v.last)) + .map(v => Map("client_id" -> v.head, "client_secret" -> v.tail.mkString(":"))) .getOrElse(Map.empty[String, String]) f(map) } @@ -438,7 +438,7 @@ class ClientCredentialFlow extends RequestTransformer { .map(v => new String(v)) .filter(_.contains(":")) .map(_.split(":").toSeq) - .map(v => Map("client_id" -> v.head, "client_secret" -> v.last)) + .map(v => Map("client_id" -> v.head, "client_secret" -> v.tail.mkString(":"))) .getOrElse(Map.empty[String, String]) f(map) } @@ -772,7 +772,7 @@ class ClientCredentialFlow extends RequestTransformer { .map(v => new String(v)) .filter(_.contains(":")) .map(_.split(":").toSeq) - .map(v => (v.head, v.last)) + .map(v => (v.head, v.tail.mkString(":"))) .map { case (clientId, clientSecret) => handleTokenRequest( ClientCredentialFlowBody( @@ -814,7 +814,7 @@ class ClientCredentialFlow extends RequestTransformer { .map(v => new String(v)) .filter(_.contains(":")) .map(_.split(":").toSeq) - .map(v => (v.head, v.last)) + .map(v => (v.head, v.tail.mkString(":"))) .map { case (clientId, clientSecret) => handleTokenRequest( ClientCredentialFlowBody( @@ -1038,7 +1038,7 @@ class ClientCredentialService extends RequestSink { .map(v => new String(v)) .filter(_.contains(":")) .map(_.split(":").toSeq) - .map(v => Map("client_id" -> v.head, "client_secret" -> v.last)) + .map(v => Map("client_id" -> v.head, "client_secret" -> v.tail.mkString(":"))) .getOrElse(Map.empty[String, String]) f(map) } @@ -1056,7 +1056,7 @@ class ClientCredentialService extends RequestSink { .map(v => new String(v)) .filter(_.contains(":")) .map(_.split(":").toSeq) - .map(v => Map("client_id" -> v.head, "client_secret" -> v.last)) + .map(v => Map("client_id" -> v.head, "client_secret" -> v.tail.mkString(":"))) .getOrElse(Map.empty[String, String]) f(map) } @@ -1344,7 +1344,7 @@ class ClientCredentialService extends RequestSink { .map(v => new String(v)) .filter(_.contains(":")) .map(_.split(":").toSeq) - .map(v => (v.head, v.last)) + .map(v => (v.head, v.tail.mkString(":"))) .map { case (clientId, clientSecret) => handleTokenRequest( ClientCredentialFlowBody( @@ -1430,7 +1430,8 @@ class ApikeyAuthModule extends PreRouting { Option(base64) .map(decodeBase64) .map(_.split(":").toSeq) - .flatMap(a => a.headOption.flatMap(head => a.lastOption.map(last => (head, last)))) + .filter(v => v.nonEmpty && v.length > 1) + .flatMap(a => a.headOption.map(head => (head, a.tail.mkString(":")))) } def unauthorized(ctx: PreRoutingContext): Future[Unit] = { diff --git a/otoroshi/app/plugins/body.scala b/otoroshi/app/plugins/body.scala index 48516018e0..695b5b619d 100644 --- a/otoroshi/app/plugins/body.scala +++ b/otoroshi/app/plugins/body.scala @@ -241,7 +241,8 @@ class BodyLogger extends RequestTransformer { Option(base64) .map(decodeBase64) .map(_.split(":").toSeq) - .flatMap(a => a.headOption.flatMap(head => a.lastOption.map(last => (head, last)))) + .filter(v => v.nonEmpty && v.length > 1) + .flatMap(a => a.headOption.map(head => (head, a.tail.mkString(":")))) } private def set(key: String, value: ByteString, ttl: Option[Long])(implicit diff --git a/otoroshi/app/plugins/core/apikeys.scala b/otoroshi/app/plugins/core/apikeys.scala index b25ca5964d..e1c2d152b1 100644 --- a/otoroshi/app/plugins/core/apikeys.scala +++ b/otoroshi/app/plugins/core/apikeys.scala @@ -246,8 +246,9 @@ class BasicAuthApikeyExtractor extends PreRouting { ) if (authBasic.isDefined && descriptor.apiKeyConstraints.basicAuth.enabled) { val auth = authBasic.get - val id = auth.split(":").headOption.map(_.trim) - val secret = auth.split(":").lastOption.map(_.trim) + val parts = auth.split(":") + val id = parts.headOption.map(_.trim) + val secret = if (parts.length > 1) parts.tail.mkString(":").trim.some else None (id, secret) match { case (Some(apiKeyClientId), Some(apiKeySecret)) => { env.datastores.apiKeyDataStore