Skip to content

Commit d6bebf6

Browse files
committed
fix: should fix cookie issues for https and http
1 parent 4d7a253 commit d6bebf6

1 file changed

Lines changed: 57 additions & 8 deletions

File tree

Pano/src/main/kotlin/com/panomc/platform/auth/AuthProvider.kt

Lines changed: 57 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import com.panomc.platform.util.Regexes
1212
import com.panomc.platform.util.TextUtil
1313
import io.vertx.core.http.Cookie
1414
import io.vertx.core.http.CookieSameSite
15+
import io.vertx.core.http.HttpServerRequest
1516
import io.vertx.ext.web.RoutingContext
1617
import io.vertx.sqlclient.SqlClient
1718
import org.springframework.beans.factory.config.ConfigurableBeanFactory
@@ -123,14 +124,7 @@ class AuthProvider(
123124
val response = routingContext.response()
124125
val request = routingContext.request()
125126
val domain = resolveCookieDomain(routingContext)
126-
val forwardedProto = request.getHeader("X-Forwarded-Proto")
127-
?.split(",")
128-
?.firstOrNull()
129-
?.trim()
130-
?.lowercase()
131-
132-
// Secure flag should follow the effective request protocol, not website-url config.
133-
val isSecure = request.isSSL || forwardedProto == "https"
127+
val isSecure = effectiveConnectionIsSecure(request)
134128

135129
val authTokenCookie = Cookie.cookie(getJwtCookieName(isSecure), authToken)
136130
val csrfTokenCookie = Cookie.cookie(getCsrfCookieName(isSecure), csrfToken)
@@ -170,6 +164,61 @@ class AuthProvider(
170164
return true
171165
}
172166

167+
/**
168+
* TLS is often terminated before Vert.x; infer HTTPS only from the connection and trusted proxy headers.
169+
* If a proxy explicitly says `http`, cookies stay non-secure. No `website-url` involvement.
170+
*/
171+
private fun effectiveConnectionIsSecure(request: HttpServerRequest): Boolean {
172+
if (request.isSSL) {
173+
return true
174+
}
175+
176+
val xfp = commaSeparatedTokens(request.getHeader("X-Forwarded-Proto"))
177+
if (xfp.any { it == "https" }) {
178+
return true
179+
}
180+
if (xfp.any { it == "http" }) {
181+
return false
182+
}
183+
184+
val xForwardedProtocol = commaSeparatedTokens(request.getHeader("X-Forwarded-Protocol"))
185+
if (xForwardedProtocol.any { it == "https" }) {
186+
return true
187+
}
188+
if (xForwardedProtocol.any { it == "http" }) {
189+
return false
190+
}
191+
192+
when (request.getHeader("CF-Connecting-Proto")?.trim()?.lowercase()) {
193+
"https" -> return true
194+
"http" -> return false
195+
else -> { /* continue */ }
196+
}
197+
198+
if (forwardedHeaderHasProtoHttps(request.getHeader("Forwarded"))) {
199+
return true
200+
}
201+
202+
return false
203+
}
204+
205+
private fun commaSeparatedTokens(header: String?): List<String> =
206+
header?.split(",")?.map { it.trim().lowercase() }?.filter { it.isNotEmpty() }.orEmpty()
207+
208+
private fun forwardedHeaderHasProtoHttps(header: String?): Boolean {
209+
if (header.isNullOrBlank()) {
210+
return false
211+
}
212+
return header.split(",").any { part ->
213+
part.split(";").any { param ->
214+
val kv = param.trim().split("=", limit = 2)
215+
kv.size == 2 &&
216+
kv[0].trim().equals("proto", ignoreCase = true) &&
217+
kv[1].trim().equals("https", ignoreCase = true)
218+
}
219+
}
220+
}
221+
173222
private fun resolveCookieDomain(routingContext: RoutingContext): String? {
174223
val remoteIP = getRemoteIP(routingContext)
175224

0 commit comments

Comments
 (0)