mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-08 03:08:45 +00:00
[Bug Fix] SCIM - Ensure new user roles are applied (#12015)
* SCIM fix new user roles * test_create_user_defaults_to_viewer * test_create_user_uses_default_internal_user_params_role * fix default user for SCIM * fix linting error
This commit is contained in:
parent
a5ce1cd49b
commit
b9feb43dac
2 changed files with 103 additions and 1 deletions
|
|
@ -18,6 +18,7 @@ from fastapi import (
|
|||
Response,
|
||||
)
|
||||
|
||||
import litellm
|
||||
from litellm._logging import verbose_proxy_logger
|
||||
from litellm.litellm_core_utils.safe_json_dumps import safe_dumps
|
||||
from litellm.proxy._types import (
|
||||
|
|
@ -361,6 +362,18 @@ async def create_user(
|
|||
# Create user in database
|
||||
user_id = user.userName or str(uuid.uuid4())
|
||||
metadata = _build_scim_metadata(user_data["given_name"], user_data["family_name"])
|
||||
|
||||
default_role: Optional[
|
||||
Literal[
|
||||
LitellmUserRoles.PROXY_ADMIN,
|
||||
LitellmUserRoles.PROXY_ADMIN_VIEW_ONLY,
|
||||
LitellmUserRoles.INTERNAL_USER,
|
||||
LitellmUserRoles.INTERNAL_USER_VIEW_ONLY,
|
||||
]
|
||||
] = LitellmUserRoles.INTERNAL_USER_VIEW_ONLY
|
||||
if litellm.default_internal_user_params:
|
||||
default_role = litellm.default_internal_user_params.get("user_role")
|
||||
|
||||
new_user_request = NewUserRequest(
|
||||
user_id=user_id,
|
||||
user_email=user_data["user_email"],
|
||||
|
|
@ -368,6 +381,7 @@ async def create_user(
|
|||
teams=user_data["teams"],
|
||||
metadata=metadata,
|
||||
auto_create_key=False,
|
||||
user_role=default_role,
|
||||
)
|
||||
|
||||
# Check if user with email already exists and update if found
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ from unittest.mock import AsyncMock
|
|||
import pytest
|
||||
from fastapi import HTTPException
|
||||
|
||||
from litellm.proxy._types import NewUserRequest, ProxyException
|
||||
from litellm.proxy._types import LitellmUserRoles, NewUserRequest, ProxyException
|
||||
from litellm.proxy.management_endpoints.scim.scim_v2 import (
|
||||
UserProvisionerHelpers,
|
||||
_handle_team_membership_changes,
|
||||
|
|
@ -58,6 +58,94 @@ async def test_create_user_existing_user_conflict(mocker):
|
|||
mocked_new_user.assert_not_called()
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_create_user_defaults_to_viewer(mocker, monkeypatch):
|
||||
"""If no role provided, new user should default to viewer"""
|
||||
|
||||
scim_user = SCIMUser(
|
||||
schemas=["urn:ietf:params:scim:schemas:core:2.0:User"],
|
||||
userName="new-user",
|
||||
name=SCIMUserName(familyName="User", givenName="New"),
|
||||
emails=[SCIMUserEmail(value="new@example.com")],
|
||||
)
|
||||
|
||||
mock_prisma_client = mocker.MagicMock()
|
||||
mock_prisma_client.db = mocker.MagicMock()
|
||||
mock_prisma_client.db.litellm_usertable = mocker.MagicMock()
|
||||
mock_prisma_client.db.litellm_usertable.find_unique = AsyncMock(return_value=None)
|
||||
mock_prisma_client.db.litellm_usertable.find_first = AsyncMock(return_value=None)
|
||||
|
||||
monkeypatch.setattr(
|
||||
"litellm.default_internal_user_params", None, raising=False
|
||||
)
|
||||
|
||||
mocker.patch(
|
||||
"litellm.proxy.management_endpoints.scim.scim_v2._get_prisma_client_or_raise_exception",
|
||||
AsyncMock(return_value=mock_prisma_client),
|
||||
)
|
||||
|
||||
new_user_mock = mocker.patch(
|
||||
"litellm.proxy.management_endpoints.scim.scim_v2.new_user",
|
||||
AsyncMock(return_value=NewUserRequest(user_id="new-user")),
|
||||
)
|
||||
|
||||
mocker.patch(
|
||||
"litellm.proxy.management_endpoints.scim.scim_v2.ScimTransformations.transform_litellm_user_to_scim_user",
|
||||
AsyncMock(return_value=scim_user),
|
||||
)
|
||||
|
||||
await create_user(user=scim_user)
|
||||
|
||||
called_args = new_user_mock.call_args.kwargs["data"]
|
||||
assert called_args.user_role == LitellmUserRoles.INTERNAL_USER_VIEW_ONLY
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_create_user_uses_default_internal_user_params_role(mocker, monkeypatch):
|
||||
"""If role is set in default_internal_user_params, new user should use that role"""
|
||||
|
||||
scim_user = SCIMUser(
|
||||
schemas=["urn:ietf:params:scim:schemas:core:2.0:User"],
|
||||
userName="new-user",
|
||||
name=SCIMUserName(familyName="User", givenName="New"),
|
||||
emails=[SCIMUserEmail(value="new@example.com")],
|
||||
)
|
||||
|
||||
mock_prisma_client = mocker.MagicMock()
|
||||
mock_prisma_client.db = mocker.MagicMock()
|
||||
mock_prisma_client.db.litellm_usertable = mocker.MagicMock()
|
||||
mock_prisma_client.db.litellm_usertable.find_unique = AsyncMock(return_value=None)
|
||||
mock_prisma_client.db.litellm_usertable.find_first = AsyncMock(return_value=None)
|
||||
|
||||
# Set default_internal_user_params with a specific role
|
||||
default_params = {
|
||||
"user_role": LitellmUserRoles.PROXY_ADMIN,
|
||||
}
|
||||
monkeypatch.setattr(
|
||||
"litellm.default_internal_user_params", default_params, raising=False
|
||||
)
|
||||
|
||||
mocker.patch(
|
||||
"litellm.proxy.management_endpoints.scim.scim_v2._get_prisma_client_or_raise_exception",
|
||||
AsyncMock(return_value=mock_prisma_client),
|
||||
)
|
||||
|
||||
new_user_mock = mocker.patch(
|
||||
"litellm.proxy.management_endpoints.scim.scim_v2.new_user",
|
||||
AsyncMock(return_value=NewUserRequest(user_id="new-user")),
|
||||
)
|
||||
|
||||
mocker.patch(
|
||||
"litellm.proxy.management_endpoints.scim.scim_v2.ScimTransformations.transform_litellm_user_to_scim_user",
|
||||
AsyncMock(return_value=scim_user),
|
||||
)
|
||||
|
||||
await create_user(user=scim_user)
|
||||
|
||||
called_args = new_user_mock.call_args.kwargs["data"]
|
||||
assert called_args.user_role == LitellmUserRoles.PROXY_ADMIN
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_handle_existing_user_by_email_no_email(mocker):
|
||||
"""Should return None when new_user_request has no email"""
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue