mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-04 02:31:27 +00:00
fix(proxy): scope auth token cookie path to SERVER_ROOT_PATH
When SERVER_ROOT_PATH is set, the login token cookie was written with the default path of "/", so deployments served under different root paths on the same host (for example a.com and a.com/prefix) overwrote each other's auth cookie and bounced users to /sso/key/generate. Set the cookie path to the normalized server root path so cookies stay isolated per deployment.
This commit is contained in:
parent
e058aa68c4
commit
b5edd4acfc
4 changed files with 38 additions and 1 deletions
|
|
@ -119,6 +119,7 @@ from litellm.proxy.management_endpoints.types import (
|
|||
from litellm.proxy.utils import (
|
||||
PrismaClient,
|
||||
ProxyLogging,
|
||||
get_cookie_path_from_server_root_path,
|
||||
get_custom_url,
|
||||
get_server_root_path,
|
||||
)
|
||||
|
|
@ -2796,6 +2797,7 @@ def set_session_token_cookie(response: Response, request: Request, jwt_token: st
|
|||
response.set_cookie(
|
||||
key="token",
|
||||
value=jwt_token,
|
||||
path=get_cookie_path_from_server_root_path(),
|
||||
secure=IPAddressUtils.is_request_https(request),
|
||||
httponly=False,
|
||||
samesite="lax",
|
||||
|
|
|
|||
|
|
@ -645,6 +645,7 @@ from litellm.proxy.utils import (
|
|||
_is_valid_team_configs,
|
||||
evict_config_param,
|
||||
get_config_param,
|
||||
get_cookie_path_from_server_root_path,
|
||||
get_custom_url,
|
||||
get_error_message_str,
|
||||
get_server_root_path,
|
||||
|
|
|
|||
|
|
@ -7219,6 +7219,20 @@ def get_server_root_path() -> str:
|
|||
return os.getenv("SERVER_ROOT_PATH", "")
|
||||
|
||||
|
||||
def get_cookie_path_from_server_root_path() -> str:
|
||||
"""
|
||||
Cookie `path` scoped to SERVER_ROOT_PATH.
|
||||
|
||||
Ensures auth cookies for deployments served under different root paths
|
||||
(e.g. `a.com` vs `a.com/prefix`) do not overwrite each other. Defaults to
|
||||
"/" when SERVER_ROOT_PATH is unset.
|
||||
"""
|
||||
root_path = get_server_root_path()
|
||||
if not root_path or root_path == "/":
|
||||
return "/"
|
||||
return "/" + root_path.strip("/")
|
||||
|
||||
|
||||
def normalize_route_for_root_path(route: str) -> str | None:
|
||||
"""Strip SERVER_ROOT_PATH prefix. Returns de-prefixed route, or None if route is not under root path."""
|
||||
root_path: Final = get_server_root_path()
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ from litellm.types.guardrails import GuardrailEventHooks
|
|||
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
from litellm.proxy.utils import get_custom_url, join_paths
|
||||
from litellm.proxy.utils import get_cookie_path_from_server_root_path, get_custom_url, join_paths
|
||||
|
||||
|
||||
def test_get_custom_url(monkeypatch):
|
||||
|
|
@ -22,6 +22,26 @@ def test_get_custom_url(monkeypatch):
|
|||
assert custom_url == "http://0.0.0.0:4000/litellm/ui/"
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"server_root_path, expected",
|
||||
[
|
||||
(None, "/"),
|
||||
("", "/"),
|
||||
("/", "/"),
|
||||
("/litellm", "/litellm"),
|
||||
("litellm", "/litellm"),
|
||||
("/litellm/", "/litellm"),
|
||||
("/team/a", "/team/a"),
|
||||
],
|
||||
)
|
||||
def test_get_cookie_path_from_server_root_path(monkeypatch, server_root_path, expected):
|
||||
if server_root_path is None:
|
||||
monkeypatch.delenv("SERVER_ROOT_PATH", raising=False)
|
||||
else:
|
||||
monkeypatch.setenv("SERVER_ROOT_PATH", server_root_path)
|
||||
assert get_cookie_path_from_server_root_path() == expected
|
||||
|
||||
|
||||
def test_proxy_only_error_true_for_llm_route():
|
||||
proxy_logging_obj = ProxyLogging(user_api_key_cache=DualCache())
|
||||
assert proxy_logging_obj._is_proxy_only_llm_api_error(
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue