mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-26 01:12:21 +00:00
fix(sso): gate /sso/debug routes behind ENABLE_SSO_DEBUG, off by default (#43150)
/sso/debug/login and /sso/debug/callback are diagnostic pages that had no off switch. They cannot carry a bearer credential because the IdP redirects a bare browser to the callback, so the gate is an explicit opt-in flag rather than key auth: both routes return 404 unless ENABLE_SSO_DEBUG is set to a truthy value.
This commit is contained in:
parent
f6882246d4
commit
88fd15315c
2 changed files with 45 additions and 3 deletions
|
|
@ -4618,6 +4618,13 @@ class GoogleSSOHandler:
|
|||
return result or {}
|
||||
|
||||
|
||||
def _raise_if_sso_debug_disabled() -> None:
|
||||
"""The debug routes run the browser-redirect SSO flow, so they cannot carry a
|
||||
bearer credential; an explicit opt-in flag is the only way to gate them."""
|
||||
if get_secret_bool("ENABLE_SSO_DEBUG") is not True:
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Not Found")
|
||||
|
||||
|
||||
@router.get("/sso/debug/login", tags=["experimental"], include_in_schema=False)
|
||||
async def debug_sso_login(request: Request):
|
||||
"""
|
||||
|
|
@ -4625,6 +4632,8 @@ async def debug_sso_login(request: Request):
|
|||
PROXY_BASE_URL should be the your deployed proxy endpoint, e.g. PROXY_BASE_URL="https://litellm-production-7002.up.railway.app/"
|
||||
Example:
|
||||
"""
|
||||
_raise_if_sso_debug_disabled()
|
||||
|
||||
from litellm.proxy.proxy_server import premium_user
|
||||
|
||||
microsoft_client_id: Final = os.getenv("MICROSOFT_CLIENT_ID", None)
|
||||
|
|
@ -4670,6 +4679,8 @@ async def debug_sso_callback(request: Request):
|
|||
"""
|
||||
Returns the OpenID object returned by the SSO provider
|
||||
"""
|
||||
_raise_if_sso_debug_disabled()
|
||||
|
||||
import json
|
||||
|
||||
from fastapi.responses import HTMLResponse
|
||||
|
|
|
|||
|
|
@ -8029,6 +8029,37 @@ class TestPKCEStateCookieBinding:
|
|||
assert result is not None
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.parametrize("enable_sso_debug_value", [None, "false", "0"])
|
||||
async def test_sso_debug_routes_return_404_unless_explicitly_enabled(enable_sso_debug_value):
|
||||
"""
|
||||
/sso/debug/login and /sso/debug/callback must 404 unless ENABLE_SSO_DEBUG is
|
||||
explicitly set to a truthy value.
|
||||
"""
|
||||
from litellm.proxy.management_endpoints.ui_sso import debug_sso_callback, debug_sso_login
|
||||
|
||||
mock_request = MagicMock(spec=Request)
|
||||
mock_request.base_url = "http://proxy.example.com/"
|
||||
mock_request.cookies = {}
|
||||
mock_request.query_params = {}
|
||||
|
||||
env = {"GENERIC_CLIENT_ID": "test_client_id"}
|
||||
if enable_sso_debug_value is not None:
|
||||
env["ENABLE_SSO_DEBUG"] = enable_sso_debug_value
|
||||
|
||||
with patch.dict(os.environ, env, clear=False):
|
||||
if enable_sso_debug_value is None:
|
||||
os.environ.pop("ENABLE_SSO_DEBUG", None)
|
||||
|
||||
with pytest.raises(HTTPException) as login_exc:
|
||||
await debug_sso_login(mock_request)
|
||||
with pytest.raises(HTTPException) as callback_exc:
|
||||
await debug_sso_callback(mock_request)
|
||||
|
||||
assert login_exc.value.status_code == 404
|
||||
assert callback_exc.value.status_code == 404
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_debug_sso_callback_renders_full_jwt_claims():
|
||||
"""
|
||||
|
|
@ -8080,7 +8111,7 @@ async def test_debug_sso_callback_renders_full_jwt_claims():
|
|||
with (
|
||||
patch.dict(
|
||||
os.environ,
|
||||
{"GENERIC_CLIENT_ID": "test_client_id"},
|
||||
{"GENERIC_CLIENT_ID": "test_client_id", "ENABLE_SSO_DEBUG": "true"},
|
||||
clear=False,
|
||||
),
|
||||
patch(
|
||||
|
|
@ -8165,7 +8196,7 @@ async def test_debug_sso_callback_handles_missing_raw_response():
|
|||
with (
|
||||
patch.dict(
|
||||
os.environ,
|
||||
{"MICROSOFT_CLIENT_ID": "test_microsoft_id"},
|
||||
{"MICROSOFT_CLIENT_ID": "test_microsoft_id", "ENABLE_SSO_DEBUG": "true"},
|
||||
clear=False,
|
||||
),
|
||||
patch.object(
|
||||
|
|
@ -8213,7 +8244,7 @@ async def _render_debug_page(provider_env, id_jag_registered, force_inert=False)
|
|||
return parsed
|
||||
|
||||
stack = [
|
||||
patch.dict(os.environ, provider_env, clear=False),
|
||||
patch.dict(os.environ, {**provider_env, "ENABLE_SSO_DEBUG": "true"}, clear=False),
|
||||
patch( # test-quality-ok: endpoint test stubs the upstream generic IdP boundary
|
||||
"litellm.proxy.management_endpoints.ui_sso.get_generic_sso_response", side_effect=fake_generic
|
||||
),
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue