mirror of
https://github.com/BerriAI/litellm.git
synced 2025-04-26 11:14:04 +00:00
(feat proxy) [beta] add support for organization role based access controls (#6112)
* track LiteLLM_OrganizationMembership * add add_internal_user_to_organization * add org membership to schema * read organization membership when reading user info in auth checks * add check for valid organization_id * add test for test_create_new_user_in_organization * test test_create_new_user_in_organization * add new ADMIN role * add test for org admins creating teams * add test for test_org_admin_create_user_permissions * test_org_admin_create_user_team_wrong_org_permissions * test_org_admin_create_user_team_wrong_org_permissions * fix organization_role_based_access_check * fix getting user members * fix TeamBase * fix types used for use role * fix type checks * sync prisma schema * docs - organization admins * fix use organization_endpoints for /organization management * add types for org member endpoints * fix role name for org admin * add type for member add response * add organization/member_add * add error handling for adding members to an org * add nice doc string for oranization/member_add * fix test_create_new_user_in_organization * linting fix * use simple route changes * fix types * add organization member roles * add org admin auth checks * add auth checks for orgs * test for creating teams as org admin * simplify org id usage * fix typo * test test_org_admin_create_user_team_wrong_org_permissions * fix type check issue * code quality fix * fix schema.prisma
This commit is contained in:
parent
d1c739f312
commit
a163464197
14 changed files with 1474 additions and 261 deletions
|
@ -32,6 +32,8 @@ from litellm.proxy.auth.route_checks import is_llm_api_route
|
|||
from litellm.proxy.utils import PrismaClient, ProxyLogging, log_to_opentelemetry
|
||||
from litellm.types.services import ServiceLoggerPayload, ServiceTypes
|
||||
|
||||
from .auth_checks_organization import organization_role_based_access_check
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from opentelemetry.trace import Span as _Span
|
||||
|
||||
|
@ -63,6 +65,7 @@ def common_checks(
|
|||
7. [OPTIONAL] If 'litellm.max_budget' is set (>0), is proxy under budget
|
||||
8. [OPTIONAL] If guardrails modified - is request allowed to change this
|
||||
9. Check if request body is safe
|
||||
10. [OPTIONAL] Organization checks - is user_object.organization_id is set, run these checks
|
||||
"""
|
||||
_model = request_body.get("model", None)
|
||||
if team_object is not None and team_object.blocked is True:
|
||||
|
@ -73,6 +76,7 @@ def common_checks(
|
|||
if (
|
||||
_model is not None
|
||||
and team_object is not None
|
||||
and team_object.models is not None
|
||||
and len(team_object.models) > 0
|
||||
and _model not in team_object.models
|
||||
):
|
||||
|
@ -202,6 +206,12 @@ def common_checks(
|
|||
"error": "Your team does not have permission to modify guardrails."
|
||||
},
|
||||
)
|
||||
|
||||
# 10 [OPTIONAL] Organization RBAC checks
|
||||
organization_role_based_access_check(
|
||||
user_object=user_object, route=route, request_body=request_body
|
||||
)
|
||||
|
||||
return True
|
||||
|
||||
|
||||
|
@ -403,17 +413,30 @@ async def get_user_object(
|
|||
try:
|
||||
|
||||
response = await prisma_client.db.litellm_usertable.find_unique(
|
||||
where={"user_id": user_id}
|
||||
where={"user_id": user_id}, include={"organization_memberships": True}
|
||||
)
|
||||
|
||||
if response is None:
|
||||
if user_id_upsert:
|
||||
response = await prisma_client.db.litellm_usertable.create(
|
||||
data={"user_id": user_id}
|
||||
data={"user_id": user_id},
|
||||
include={"organization_memberships": True},
|
||||
)
|
||||
else:
|
||||
raise Exception
|
||||
|
||||
if (
|
||||
response.organization_memberships is not None
|
||||
and len(response.organization_memberships) > 0
|
||||
):
|
||||
# dump each organization membership to type LiteLLM_OrganizationMembershipTable
|
||||
_dumped_memberships = [
|
||||
membership.model_dump()
|
||||
for membership in response.organization_memberships
|
||||
if membership is not None
|
||||
]
|
||||
response.organization_memberships = _dumped_memberships
|
||||
|
||||
_response = LiteLLM_UserTable(**dict(response))
|
||||
response_dict = _response.model_dump()
|
||||
|
||||
|
@ -421,9 +444,9 @@ async def get_user_object(
|
|||
await user_api_key_cache.async_set_cache(key=user_id, value=response_dict)
|
||||
|
||||
return _response
|
||||
except Exception: # if user not in db
|
||||
except Exception as e: # if user not in db
|
||||
raise ValueError(
|
||||
f"User doesn't exist in db. 'user_id'={user_id}. Create user via `/user/new` call."
|
||||
f"User doesn't exist in db. 'user_id'={user_id}. Create user via `/user/new` call. Got error - {e}"
|
||||
)
|
||||
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue