mirror of
https://github.com/BerriAI/litellm.git
synced 2025-04-25 02:34:29 +00:00
add scim router
This commit is contained in:
parent
121fb32bbe
commit
a14d0d91e9
2 changed files with 139 additions and 19 deletions
125
litellm/proxy/management_endpoints/README_SCIM.md
Normal file
125
litellm/proxy/management_endpoints/README_SCIM.md
Normal file
|
@ -0,0 +1,125 @@
|
|||
# SCIM v2 Integration for LiteLLM Proxy
|
||||
|
||||
This module provides SCIM v2 (System for Cross-domain Identity Management) endpoints for LiteLLM Proxy, allowing identity providers to manage users and teams (groups) within the LiteLLM ecosystem.
|
||||
|
||||
## Overview
|
||||
|
||||
SCIM is an open standard designed to simplify user management across different systems. This implementation allows compatible identity providers (like Okta, Azure AD, OneLogin, etc.) to automatically provision and deprovision users and groups in LiteLLM Proxy.
|
||||
|
||||
## Endpoints
|
||||
|
||||
The SCIM v2 API follows the standard specification with the following base URL:
|
||||
|
||||
```
|
||||
/scim/v2
|
||||
```
|
||||
|
||||
### User Management
|
||||
|
||||
| Endpoint | Method | Description |
|
||||
|----------|--------|-------------|
|
||||
| `/Users` | GET | List all users with pagination support |
|
||||
| `/Users/{user_id}` | GET | Get a specific user by ID |
|
||||
| `/Users` | POST | Create a new user |
|
||||
| `/Users/{user_id}` | PUT | Update an existing user |
|
||||
| `/Users/{user_id}` | DELETE | Delete a user |
|
||||
|
||||
### Group Management
|
||||
|
||||
| Endpoint | Method | Description |
|
||||
|----------|--------|-------------|
|
||||
| `/Groups` | GET | List all groups with pagination support |
|
||||
| `/Groups/{group_id}` | GET | Get a specific group by ID |
|
||||
| `/Groups` | POST | Create a new group |
|
||||
| `/Groups/{group_id}` | PUT | Update an existing group |
|
||||
| `/Groups/{group_id}` | DELETE | Delete a group |
|
||||
|
||||
## SCIM Schema
|
||||
|
||||
This implementation follows the standard SCIM v2 schema with the following mappings:
|
||||
|
||||
### Users
|
||||
|
||||
- SCIM User ID → LiteLLM `user_id`
|
||||
- SCIM User Email → LiteLLM `user_email`
|
||||
- SCIM User Group Memberships → LiteLLM User-Team relationships
|
||||
|
||||
### Groups
|
||||
|
||||
- SCIM Group ID → LiteLLM `team_id`
|
||||
- SCIM Group Display Name → LiteLLM `team_alias`
|
||||
- SCIM Group Members → LiteLLM Team members list
|
||||
|
||||
## Configuration
|
||||
|
||||
To enable SCIM in your identity provider, use the full URL to the SCIM endpoint:
|
||||
|
||||
```
|
||||
https://your-litellm-proxy-url/scim/v2
|
||||
```
|
||||
|
||||
Most identity providers will require authentication. You should use a valid LiteLLM API key with administrative privileges.
|
||||
|
||||
## Features
|
||||
|
||||
- Full CRUD operations for users and groups
|
||||
- Pagination support
|
||||
- Basic filtering support
|
||||
- Automatic synchronization of user-team relationships
|
||||
- Proper status codes and error handling per SCIM specification
|
||||
|
||||
## Limitations
|
||||
|
||||
This is a basic implementation intended for testing and integration purposes. Some limitations include:
|
||||
|
||||
- Limited filtering capabilities (only supports basic equality filters)
|
||||
- No support for complex SCIM operations like PATCH
|
||||
- Limited schema customization
|
||||
|
||||
## Example Usage
|
||||
|
||||
### Listing Users
|
||||
|
||||
```
|
||||
GET /scim/v2/Users?startIndex=1&count=10
|
||||
```
|
||||
|
||||
### Creating a User
|
||||
|
||||
```json
|
||||
POST /scim/v2/Users
|
||||
{
|
||||
"schemas": ["urn:ietf:params:scim:schemas:core:2.0:User"],
|
||||
"userName": "john.doe@example.com",
|
||||
"active": true,
|
||||
"emails": [
|
||||
{
|
||||
"value": "john.doe@example.com",
|
||||
"primary": true
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### Adding a User to Groups
|
||||
|
||||
```json
|
||||
PUT /scim/v2/Users/{user_id}
|
||||
{
|
||||
"schemas": ["urn:ietf:params:scim:schemas:core:2.0:User"],
|
||||
"userName": "john.doe@example.com",
|
||||
"active": true,
|
||||
"emails": [
|
||||
{
|
||||
"value": "john.doe@example.com",
|
||||
"primary": true
|
||||
}
|
||||
],
|
||||
"groups": [
|
||||
{
|
||||
"value": "team-123",
|
||||
"display": "Engineering Team"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
|
@ -238,6 +238,7 @@ from litellm.proxy.management_endpoints.model_management_endpoints import (
|
|||
from litellm.proxy.management_endpoints.organization_endpoints import (
|
||||
router as organization_router,
|
||||
)
|
||||
from litellm.proxy.management_endpoints.scim_v2 import scim_router
|
||||
from litellm.proxy.management_endpoints.tag_management_endpoints import (
|
||||
router as tag_management_router,
|
||||
)
|
||||
|
@ -803,9 +804,9 @@ model_max_budget_limiter = _PROXY_VirtualKeyModelMaxBudgetLimiter(
|
|||
dual_cache=user_api_key_cache
|
||||
)
|
||||
litellm.logging_callback_manager.add_litellm_callback(model_max_budget_limiter)
|
||||
redis_usage_cache: Optional[
|
||||
RedisCache
|
||||
] = None # redis cache used for tracking spend, tpm/rpm limits
|
||||
redis_usage_cache: Optional[RedisCache] = (
|
||||
None # redis cache used for tracking spend, tpm/rpm limits
|
||||
)
|
||||
user_custom_auth = None
|
||||
user_custom_key_generate = None
|
||||
user_custom_sso = None
|
||||
|
@ -1131,9 +1132,9 @@ async def update_cache( # noqa: PLR0915
|
|||
_id = "team_id:{}".format(team_id)
|
||||
try:
|
||||
# Fetch the existing cost for the given user
|
||||
existing_spend_obj: Optional[
|
||||
LiteLLM_TeamTable
|
||||
] = await user_api_key_cache.async_get_cache(key=_id)
|
||||
existing_spend_obj: Optional[LiteLLM_TeamTable] = (
|
||||
await user_api_key_cache.async_get_cache(key=_id)
|
||||
)
|
||||
if existing_spend_obj is None:
|
||||
# do nothing if team not in api key cache
|
||||
return
|
||||
|
@ -1807,13 +1808,6 @@ class ProxyConfig:
|
|||
if master_key and master_key.startswith("os.environ/"):
|
||||
master_key = get_secret(master_key) # type: ignore
|
||||
|
||||
if not isinstance(master_key, str):
|
||||
raise Exception(
|
||||
"Master key must be a string. Current type - {}".format(
|
||||
type(master_key)
|
||||
)
|
||||
)
|
||||
|
||||
if master_key is not None and isinstance(master_key, str):
|
||||
litellm_master_key_hash = hash_token(master_key)
|
||||
### USER API KEY CACHE IN-MEMORY TTL ###
|
||||
|
@ -2812,9 +2806,9 @@ async def initialize( # noqa: PLR0915
|
|||
user_api_base = api_base
|
||||
dynamic_config[user_model]["api_base"] = api_base
|
||||
if api_version:
|
||||
os.environ[
|
||||
"AZURE_API_VERSION"
|
||||
] = api_version # set this for azure - litellm can read this from the env
|
||||
os.environ["AZURE_API_VERSION"] = (
|
||||
api_version # set this for azure - litellm can read this from the env
|
||||
)
|
||||
if max_tokens: # model-specific param
|
||||
dynamic_config[user_model]["max_tokens"] = max_tokens
|
||||
if temperature: # model-specific param
|
||||
|
@ -7756,9 +7750,9 @@ async def get_config_list(
|
|||
hasattr(sub_field_info, "description")
|
||||
and sub_field_info.description is not None
|
||||
):
|
||||
nested_fields[
|
||||
idx
|
||||
].field_description = sub_field_info.description
|
||||
nested_fields[idx].field_description = (
|
||||
sub_field_info.description
|
||||
)
|
||||
idx += 1
|
||||
|
||||
_stored_in_db = None
|
||||
|
@ -8176,6 +8170,7 @@ app.include_router(key_management_router)
|
|||
app.include_router(internal_user_router)
|
||||
app.include_router(team_router)
|
||||
app.include_router(ui_sso_router)
|
||||
app.include_router(scim_router)
|
||||
app.include_router(organization_router)
|
||||
app.include_router(customer_router)
|
||||
app.include_router(spend_management_router)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue