mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-12 23:01:41 +00:00
Add endpoint-level access control to /v2/user/info
Non-admin users can only query their own user_id. Previously relied solely on the auth middleware route check, which proxy admins bypass. This adds defense-in-depth directly in the handler. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
47590b4fba
commit
e6ac4cb230
2 changed files with 46 additions and 1 deletions
|
|
@ -766,6 +766,19 @@ async def user_info_v2(
|
|||
detail="user_id is required",
|
||||
)
|
||||
|
||||
# Non-admin users can only query their own info
|
||||
if (
|
||||
user_api_key_dict.user_role != LitellmUserRoles.PROXY_ADMIN
|
||||
and user_api_key_dict.user_role != LitellmUserRoles.PROXY_ADMIN_VIEW_ONLY
|
||||
and user_id != user_api_key_dict.user_id
|
||||
):
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_403_FORBIDDEN,
|
||||
detail="Not allowed to access other user's info. Your user_id={}, requested user_id={}".format(
|
||||
user_api_key_dict.user_id, user_id
|
||||
),
|
||||
)
|
||||
|
||||
user_info = await prisma_client.get_data(user_id=user_id)
|
||||
|
||||
if user_info is None:
|
||||
|
|
|
|||
|
|
@ -1508,4 +1508,36 @@ async def test_user_info_v1_has_deprecation_header(mocker):
|
|||
assert result.user_id == "test-user"
|
||||
# Deprecation headers should be set on the response object
|
||||
assert mock_response.headers.get("Deprecation") == "true"
|
||||
assert "successor-version" in mock_response.headers.get("Link", "")
|
||||
assert "successor-version" in mock_response.headers.get("Link", "")
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_user_info_v2_non_admin_cannot_query_other_user(mocker):
|
||||
"""
|
||||
Test that a non-admin user gets 403 when querying another user's info
|
||||
via /v2/user/info endpoint handler (defense-in-depth).
|
||||
"""
|
||||
from fastapi import Request
|
||||
|
||||
from litellm.proxy._types import ProxyException, UserAPIKeyAuth
|
||||
from litellm.proxy.management_endpoints.internal_user_endpoints import (
|
||||
user_info_v2,
|
||||
)
|
||||
|
||||
mock_prisma_client = mocker.MagicMock()
|
||||
mocker.patch("litellm.proxy.proxy_server.prisma_client", mock_prisma_client)
|
||||
|
||||
mock_request = mocker.MagicMock(spec=Request)
|
||||
mock_user_api_key_dict = UserAPIKeyAuth(
|
||||
user_id="user-A", user_role="internal_user"
|
||||
)
|
||||
|
||||
with pytest.raises(ProxyException) as exc_info:
|
||||
await user_info_v2(
|
||||
user_id="user-B",
|
||||
user_api_key_dict=mock_user_api_key_dict,
|
||||
request=mock_request,
|
||||
)
|
||||
|
||||
assert exc_info.value.code == "403"
|
||||
assert "Not allowed" in str(exc_info.value.message)
|
||||
Loading…
Add table
Reference in a new issue