chore: special sauce (#8646)

This commit is contained in:
Nikolas Garza authored and GitHub committed 2026-02-21 01:30:36 +00:00
1 parent fb7e7e4395
commit c142b2db02
6 files changed
+32 -76

No files matched your search

+4 -1
View File
@@ -1671,7 +1671,10 @@ def get_oauth_router(
if redirect_url is not None:
authorize_redirect_url = redirect_url
else:
authorize_redirect_url = str(request.url_for(callback_route_name))
# Use WEB_DOMAIN instead of request.url_for() to prevent host
# header poisoning — request.url_for() trusts the Host header.
callback_path = request.app.url_path_for(callback_route_name)
authorize_redirect_url = f"{WEB_DOMAIN}{callback_path}"
next_url = request.query_params.get("next", "/")
+7 -3
View File
@@ -24,6 +24,7 @@ from onyx.auth.users import get_user_manager
from onyx.auth.users import UserManager
from onyx.configs.app_configs import REQUIRE_EMAIL_VERIFICATION
from onyx.configs.app_configs import SAML_CONF_DIR
from onyx.configs.app_configs import WEB_DOMAIN
from onyx.db.auth import get_user_count
from onyx.db.auth import get_user_db
from onyx.db.engine.async_sql_engine import get_async_session_context_manager
@@ -123,9 +124,12 @@ async def prepare_from_fastapi_request(request: Request) -> dict[str, Any]:
if request.client is None:
raise ValueError("Invalid request for SAML")
# Use X-Forwarded headers if available
http_host = request.headers.get("X-Forwarded-Host") or request.client.host
server_port = request.headers.get("X-Forwarded-Port") or request.url.port
# Derive http_host and server_port from WEB_DOMAIN (a trusted env var)
# instead of X-Forwarded-* headers, which can be spoofed by an attacker
# to poison SAML redirect URLs (host header poisoning).
parsed_domain = urlparse(WEB_DOMAIN)
http_host = parsed_domain.hostname or request.client.host
server_port = parsed_domain.port or (443 if parsed_domain.scheme == "https" else 80)
rv: dict[str, Any] = {
"http_host": http_host,
@@ -4,24 +4,6 @@ log_format custom_main '$remote_addr - $remote_user [$time_local] "$request" '
'"$http_user_agent" "$http_x_forwarded_for" '
'rt=$request_time';
# Map X-Forwarded-Proto or fallback to $scheme
map $http_x_forwarded_proto $forwarded_proto {
default $http_x_forwarded_proto;
"" $scheme;
}
# Map X-Forwarded-Host or fallback to $host
map $http_x_forwarded_host $forwarded_host {
default $http_x_forwarded_host;
"" $host;
}
# Map X-Forwarded-Port or fallback to server port
map $http_x_forwarded_port $forwarded_port {
default $http_x_forwarded_port;
"" $server_port;
}
upstream api_server {
# fail_timeout=0 means we always retry an upstream even if it failed
# to return a good HTTP response
@@ -59,9 +41,10 @@ server {
# misc headers
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $forwarded_proto;
proxy_set_header X-Forwarded-Host $forwarded_host;
proxy_set_header X-Forwarded-Port $forwarded_port;
# don't trust client-supplied X-Forwarded-* headers — use nginx's own values
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Port $server_port;
proxy_set_header Host $host;
# need to use 1.1 to support chunked transfers
@@ -78,9 +61,10 @@ server {
# misc headers
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $forwarded_proto;
proxy_set_header X-Forwarded-Host $forwarded_host;
proxy_set_header X-Forwarded-Port $forwarded_port;
# don't trust client-supplied X-Forwarded-* headers — use nginx's own values
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Port $server_port;
proxy_set_header Host $host;
proxy_http_version 1.1;
+8 -24
View File
@@ -4,24 +4,6 @@ log_format custom_main '$remote_addr - $remote_user [$time_local] "$request" '
'"$http_user_agent" "$http_x_forwarded_for" '
'rt=$request_time';
# Map X-Forwarded-Proto or fallback to $scheme
map $http_x_forwarded_proto $forwarded_proto {
default $http_x_forwarded_proto;
"" $scheme;
}
# Map X-Forwarded-Host or fallback to $host
map $http_x_forwarded_host $forwarded_host {
default $http_x_forwarded_host;
"" $host;
}
# Map X-Forwarded-Port or fallback to server port
map $http_x_forwarded_port $forwarded_port {
default $http_x_forwarded_port;
"" $server_port;
}
upstream api_server {
# fail_timeout=0 means we always retry an upstream even if it failed
# to return a good HTTP response
@@ -59,9 +41,10 @@ server {
# misc headers
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $forwarded_proto;
proxy_set_header X-Forwarded-Host $forwarded_host;
proxy_set_header X-Forwarded-Port $forwarded_port;
# don't trust client-supplied X-Forwarded-* headers — use nginx's own values
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Port $server_port;
proxy_set_header Host $host;
# need to use 1.1 to support chunked transfers
@@ -83,9 +66,10 @@ server {
# misc headers
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $forwarded_proto;
proxy_set_header X-Forwarded-Host $forwarded_host;
proxy_set_header X-Forwarded-Port $forwarded_port;
# don't trust client-supplied X-Forwarded-* headers — use nginx's own values
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Port $server_port;
proxy_set_header Host $host;
proxy_http_version 1.1;
+1 -10
View File
@@ -17,16 +17,7 @@ async function handleSamlCallback(
const fetchOptions: RequestInit = {
method,
headers: {
"X-Forwarded-Host":
request.headers.get("X-Forwarded-Host") ||
request.headers.get("host") ||
"",
"X-Forwarded-Port":
request.headers.get("X-Forwarded-Port") ||
new URL(request.url).port ||
"",
},
headers: {},
};
let relayState: string | null = null;
+4 -14
View File
@@ -1,23 +1,13 @@
import { NextRequest } from "next/server";
export const getDomain = (request: NextRequest) => {
// use env variable if set
// Use the WEB_DOMAIN env variable if set (required in production).
// Never trust X-Forwarded-* headers from the request — they can be
// spoofed by an attacker to poison redirect URLs (host header poisoning).
if (process.env.WEB_DOMAIN) {
return process.env.WEB_DOMAIN;
}
// next, try and build domain from headers
const requestedHost = request.headers.get("X-Forwarded-Host");
const requestedPort = request.headers.get("X-Forwarded-Port");
const requestedProto = request.headers.get("X-Forwarded-Proto");
if (requestedHost) {
const url = request.nextUrl.clone();
url.host = requestedHost;
url.protocol = requestedProto || url.protocol;
url.port = requestedPort || url.port;
return url.origin;
}
// finally just use whatever is in the request
// Fallback for local development: use Next.js's own origin.
return request.nextUrl.origin;
};