mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-03 02:22:24 +00:00
fix(proxy): keep stored user_email when SSO login carries no email claim
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
parent
a9e9a9d6fc
commit
47c65cecff
2 changed files with 64 additions and 5 deletions
|
|
@ -1894,11 +1894,12 @@ def _build_sso_user_update_data(
|
||||||
existing_user_alias: The user's current alias in the DB; only an empty alias is filled from SSO
|
existing_user_alias: The user's current alias in the DB; only an empty alias is filled from SSO
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
dict: Update data containing user_email, user_alias when newly available, and user_role if valid
|
dict: Update data containing user_email and user_alias when the IdP supplied them, and user_role if valid
|
||||||
"""
|
"""
|
||||||
|
sso_user_email: Final = normalize_email(user_email)
|
||||||
sso_user_alias: Final = None if existing_user_alias else _get_sso_user_alias(result)
|
sso_user_alias: Final = None if existing_user_alias else _get_sso_user_alias(result)
|
||||||
update_data: Final[dict[str, object]] = {
|
update_data: Final[dict[str, object]] = {
|
||||||
"user_email": normalize_email(user_email),
|
**({"user_email": sso_user_email} if sso_user_email is not None else {}),
|
||||||
**({"user_alias": sso_user_alias} if sso_user_alias is not None else {}),
|
**({"user_alias": sso_user_alias} if sso_user_alias is not None else {}),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -3284,6 +3285,7 @@ class SSOAuthenticationHandler:
|
||||||
existing_user_alias=user_info.user_alias if isinstance(user_info, LiteLLM_UserTable) else None,
|
existing_user_alias=user_info.user_alias if isinstance(user_info, LiteLLM_UserTable) else None,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if update_data:
|
||||||
await _user_meta_db(UserRepository(prisma_client)).update_many(
|
await _user_meta_db(UserRepository(prisma_client)).update_many(
|
||||||
where={"user_id": user_id}, data=update_data
|
where={"user_id": user_id}, data=update_data
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -1141,6 +1141,63 @@ async def test_upsert_sso_user_fills_user_alias_for_existing_user():
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_build_sso_user_update_data_omits_email_when_idp_sends_none():
|
||||||
|
"""
|
||||||
|
A login without an email claim must not write user_email, so a stored email survives.
|
||||||
|
"""
|
||||||
|
from litellm.proxy.management_endpoints.types import CustomOpenID
|
||||||
|
from litellm.proxy.management_endpoints.ui_sso import _build_sso_user_update_data
|
||||||
|
|
||||||
|
sso_result = CustomOpenID(
|
||||||
|
id="S-1-5-21-adfs-user",
|
||||||
|
email=None,
|
||||||
|
display_name="Doe, Jane",
|
||||||
|
provider="generic",
|
||||||
|
team_ids=[],
|
||||||
|
)
|
||||||
|
|
||||||
|
update_data = _build_sso_user_update_data(
|
||||||
|
result=sso_result,
|
||||||
|
user_email=None,
|
||||||
|
user_id="S-1-5-21-adfs-user",
|
||||||
|
existing_user_alias=None,
|
||||||
|
)
|
||||||
|
|
||||||
|
assert update_data == {"user_alias": "Doe, Jane"}
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_upsert_sso_user_keeps_stored_email_when_idp_sends_none():
|
||||||
|
"""
|
||||||
|
An existing user whose IdP token carries no email and no new name is left untouched on login.
|
||||||
|
"""
|
||||||
|
from litellm.proxy._types import LiteLLM_UserTable
|
||||||
|
from litellm.proxy.management_endpoints.types import CustomOpenID
|
||||||
|
from litellm.proxy.management_endpoints.ui_sso import SSOAuthenticationHandler
|
||||||
|
|
||||||
|
mock_prisma = MagicMock()
|
||||||
|
mock_prisma.db.litellm_usertable.update_many = AsyncMock()
|
||||||
|
|
||||||
|
existing_user = LiteLLM_UserTable(
|
||||||
|
user_id="S-1-5-21-adfs-user",
|
||||||
|
user_email="admin.typed@example.com",
|
||||||
|
user_role="internal_user",
|
||||||
|
user_alias="Doe, Jane",
|
||||||
|
)
|
||||||
|
sso_result = CustomOpenID(id="S-1-5-21-adfs-user", email=None, provider="generic", team_ids=[])
|
||||||
|
|
||||||
|
returned = await SSOAuthenticationHandler.upsert_sso_user(
|
||||||
|
result=sso_result,
|
||||||
|
user_info=existing_user,
|
||||||
|
user_email=None,
|
||||||
|
user_defined_values=None,
|
||||||
|
prisma_client=mock_prisma,
|
||||||
|
)
|
||||||
|
|
||||||
|
assert returned is existing_user
|
||||||
|
mock_prisma.db.litellm_usertable.update_many.assert_not_called()
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_insert_sso_user_sets_user_alias_from_display_name():
|
async def test_insert_sso_user_sets_user_alias_from_display_name():
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue