diff --git a/litellm/auth_v2/config.py b/litellm/auth_v2/config.py index 16169e758ad..3e2acc7a78b 100644 --- a/litellm/auth_v2/config.py +++ b/litellm/auth_v2/config.py @@ -84,6 +84,10 @@ class SamlConfig(BaseModel): class AuthConfig(BaseModel): + # First-match-wins precedence. HTTP precedes OPENID_CONNECT, so a bearer JWT + # is claimed by HttpAuthenticator (auth_method=bearer_jwt) and OidcAuthenticator + # never runs; both share the same JwtVerifiers and verify identically, so this + # only changes the auth_method label. Reorder if openIdConnect labeling matters. scheme_order: List[SecuritySchemeType] = Field( default_factory=lambda: [ SecuritySchemeType.API_KEY, diff --git a/litellm/auth_v2/scim.py b/litellm/auth_v2/scim.py index d9a2739bbfa..0f9b13f1e33 100644 --- a/litellm/auth_v2/scim.py +++ b/litellm/auth_v2/scim.py @@ -2,7 +2,7 @@ from __future__ import annotations from typing import Any, Dict, Optional, Type, TypeVar -from fastapi import APIRouter, Request, Response, status +from fastapi import APIRouter, Request, Response, Security, status from fastapi.responses import JSONResponse from pydantic import ValidationError from scim2_models import ( @@ -23,6 +23,7 @@ from scim2_models import ( ) from .resolver import ProvisioningStore +from .security import get_current_principal R = TypeVar("R", bound=Resource) @@ -63,7 +64,11 @@ def _dump(resource: Resource, ctx: Context) -> Dict[str, Any]: def build_scim_router() -> APIRouter: - router = APIRouter(prefix="/scim/v2", tags=["scim"]) + router = APIRouter( + prefix="/scim/v2", + tags=["scim"], + dependencies=[Security(get_current_principal, scopes=["scim:write"])], + ) @router.post("/Users", status_code=status.HTTP_201_CREATED) async def create_user(request: Request) -> Response: diff --git a/litellm/auth_v2/security.py b/litellm/auth_v2/security.py index 5330509f617..7dd2721a3fb 100644 --- a/litellm/auth_v2/security.py +++ b/litellm/auth_v2/security.py @@ -31,6 +31,15 @@ def install_auth( mount_oidc: bool = True, mount_saml: bool = True, ) -> AuthContext: + """Wire the authenticators, resolver and optional routers onto the app. + + Deployment requirement for trusted-proxy IP resolution: uvicorn's + ``--proxy-headers`` (enabled by default) overwrites ``request.client`` from + ``X-Forwarded-For`` before this module's ``trusted_proxy_cidrs`` check runs, + which silently bypasses it. Run uvicorn with ``--no-proxy-headers`` and let + this module resolve the client IP, or leave ``trusted_proxy_cidrs`` empty and + rely on uvicorn's own ``--forwarded-allow-ips``. Do not enable both. + """ ctx = AuthContext(config, build_authenticators(config), resolver) app.state.auth_v2 = ctx if mount_scim: