mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-16 23:41:43 +00:00
refactor(auth_v2): split oidc/saml/scim into sub-packages
Per the revised design §2, each protocol that carries its own config/routes becomes a sub-package while the shared core stays flat. oidc.py -> oidc/router.py with oidc/config.py (OIDCProviderConfig); saml.py -> saml/router.py with saml/config.py (SAMLConfig + the attribute-map default); scim.py -> scim/router.py. Each sub-package __init__ re-exports its public names so call sites read from litellm.proxy.auth_v2.saml import SAMLConfig, build_saml_router. SessionConfig moves next to the SessionStore it configures in session.py. git mv preserves history; AuthConfig now composes the protocol configs from their sub-packages.
This commit is contained in:
parent
0ee4397a59
commit
9b9cc60994
12 changed files with 93 additions and 76 deletions
|
|
@ -4,18 +4,16 @@ from .config import (
|
|||
HttpBasicConfig,
|
||||
MutualTLSConfig,
|
||||
OAuth2IntrospectionConfig,
|
||||
OIDCProviderConfig,
|
||||
SAMLConfig,
|
||||
SessionConfig,
|
||||
TrustedProxyConfig,
|
||||
)
|
||||
from .models import Principal
|
||||
from .oidc import build_oidc_router
|
||||
from .oidc import OIDCProviderConfig, build_oidc_router
|
||||
from .rbac import Role
|
||||
from .resolver import IdentityResolver, InMemoryIdentityStore, ProvisioningStore
|
||||
from .saml import build_saml_router
|
||||
from .saml import SAMLConfig, build_saml_router
|
||||
from .scim import build_scim_router
|
||||
from .security import AuthSecurity
|
||||
from .session import SessionConfig
|
||||
|
||||
__all__ = [
|
||||
"AuthSecurity",
|
||||
|
|
|
|||
|
|
@ -21,9 +21,9 @@ from .config import (
|
|||
HttpBasicConfig,
|
||||
MutualTLSConfig,
|
||||
OAuth2IntrospectionConfig,
|
||||
OIDCProviderConfig,
|
||||
TrustedProxyConfig,
|
||||
)
|
||||
from .oidc.config import OIDCProviderConfig
|
||||
from .models import (
|
||||
AuthMethod,
|
||||
ClientCertificate,
|
||||
|
|
|
|||
|
|
@ -1,23 +1,11 @@
|
|||
from __future__ import annotations
|
||||
from typing import List, Optional
|
||||
|
||||
from typing import Dict, List, Optional
|
||||
|
||||
from pydantic import AnyHttpUrl, BaseModel, Field, SecretStr, model_validator
|
||||
from pydantic import AnyHttpUrl, BaseModel, Field, SecretStr
|
||||
|
||||
from .models import SecuritySchemeType
|
||||
|
||||
DEFAULT_SAML_ATTRIBUTE_MAP = {
|
||||
"email": "email",
|
||||
"mail": "email",
|
||||
"givenName": "given_name",
|
||||
"surname": "family_name",
|
||||
"sn": "family_name",
|
||||
"displayName": "display_name",
|
||||
"userName": "user_name",
|
||||
"uid": "user_name",
|
||||
"groups": "groups",
|
||||
"roles": "roles",
|
||||
}
|
||||
from .oidc.config import OIDCProviderConfig
|
||||
from .saml.config import SAMLConfig
|
||||
from .session import SessionConfig
|
||||
|
||||
|
||||
class ApiKeySchemeConfig(BaseModel):
|
||||
|
|
@ -29,19 +17,6 @@ class HttpBasicConfig(BaseModel):
|
|||
realm: str = "litellm"
|
||||
|
||||
|
||||
class OIDCProviderConfig(BaseModel):
|
||||
issuer: str
|
||||
audience: List[str]
|
||||
jwks_uri: Optional[AnyHttpUrl] = None
|
||||
algorithms: List[str] = Field(default_factory=lambda: ["RS256"])
|
||||
require_at_jwt: bool = False
|
||||
client_id: Optional[str] = None
|
||||
client_secret: Optional[SecretStr] = None
|
||||
login_scopes: List[str] = Field(
|
||||
default_factory=lambda: ["openid", "email", "profile"]
|
||||
)
|
||||
|
||||
|
||||
class OAuth2IntrospectionConfig(BaseModel):
|
||||
introspection_endpoint: AnyHttpUrl
|
||||
client_id: str
|
||||
|
|
@ -60,38 +35,6 @@ class TrustedProxyConfig(BaseModel):
|
|||
trusted_proxy_cidrs: List[str] = Field(default_factory=list)
|
||||
|
||||
|
||||
class SessionConfig(BaseModel):
|
||||
cookie: str = "litellm_session"
|
||||
secure: bool = True
|
||||
ttl_seconds: int = 3600
|
||||
max_size: int = 10000
|
||||
default_redirect_path: str = "/"
|
||||
login_cookie: str = "litellm_oidc_txn"
|
||||
login_state_ttl: int = 300
|
||||
|
||||
|
||||
class SAMLConfig(BaseModel):
|
||||
enabled: bool = False
|
||||
entity_id: str
|
||||
acs_url: str
|
||||
idp_metadata: str = ""
|
||||
sp_key_file: Optional[str] = None
|
||||
sp_cert_file: Optional[str] = None
|
||||
allow_unsolicited: bool = False
|
||||
xmlsec_binary: Optional[str] = None
|
||||
attribute_map: Dict[str, str] = Field(
|
||||
default_factory=lambda: dict(DEFAULT_SAML_ATTRIBUTE_MAP)
|
||||
)
|
||||
|
||||
@model_validator(mode="after")
|
||||
def _require_idp_metadata(self) -> "SAMLConfig":
|
||||
if self.enabled and not self.idp_metadata.strip():
|
||||
raise ValueError(
|
||||
"SAML enabled but idp_metadata is empty (inline XML, local path, or URL)"
|
||||
)
|
||||
return self
|
||||
|
||||
|
||||
class AuthConfig(BaseModel):
|
||||
scheme_order: List[SecuritySchemeType] = Field(
|
||||
default_factory=lambda: [
|
||||
|
|
|
|||
4
litellm/proxy/auth_v2/oidc/__init__.py
Normal file
4
litellm/proxy/auth_v2/oidc/__init__.py
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
from .config import OIDCProviderConfig
|
||||
from .router import build_oidc_router
|
||||
|
||||
__all__ = ["OIDCProviderConfig", "build_oidc_router"]
|
||||
16
litellm/proxy/auth_v2/oidc/config.py
Normal file
16
litellm/proxy/auth_v2/oidc/config.py
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
from typing import List, Optional
|
||||
|
||||
from pydantic import AnyHttpUrl, BaseModel, Field, SecretStr
|
||||
|
||||
|
||||
class OIDCProviderConfig(BaseModel):
|
||||
issuer: str
|
||||
audience: List[str]
|
||||
jwks_uri: Optional[AnyHttpUrl] = None
|
||||
algorithms: List[str] = Field(default_factory=lambda: ["RS256"])
|
||||
require_at_jwt: bool = False
|
||||
client_id: Optional[str] = None
|
||||
client_secret: Optional[SecretStr] = None
|
||||
login_scopes: List[str] = Field(
|
||||
default_factory=lambda: ["openid", "email", "profile"]
|
||||
)
|
||||
|
|
@ -9,11 +9,11 @@ from fastapi.responses import RedirectResponse
|
|||
from scim2_models import User as ScimUser
|
||||
|
||||
from .config import OIDCProviderConfig
|
||||
from .resolver import ProvisioningStore
|
||||
from .session import safe_relay_state
|
||||
from ..resolver import ProvisioningStore
|
||||
from ..session import safe_relay_state
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .security import AuthSecurity
|
||||
from ..security import AuthSecurity
|
||||
|
||||
_CLAIM_KEYS = ("email", "preferred_username", "name", "groups", "roles")
|
||||
|
||||
4
litellm/proxy/auth_v2/saml/__init__.py
Normal file
4
litellm/proxy/auth_v2/saml/__init__.py
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
from .config import SAMLConfig
|
||||
from .router import build_saml_router
|
||||
|
||||
__all__ = ["SAMLConfig", "build_saml_router"]
|
||||
38
litellm/proxy/auth_v2/saml/config.py
Normal file
38
litellm/proxy/auth_v2/saml/config.py
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
from typing import Dict, Optional
|
||||
|
||||
from pydantic import BaseModel, Field, model_validator
|
||||
|
||||
DEFAULT_SAML_ATTRIBUTE_MAP = {
|
||||
"email": "email",
|
||||
"mail": "email",
|
||||
"givenName": "given_name",
|
||||
"surname": "family_name",
|
||||
"sn": "family_name",
|
||||
"displayName": "display_name",
|
||||
"userName": "user_name",
|
||||
"uid": "user_name",
|
||||
"groups": "groups",
|
||||
"roles": "roles",
|
||||
}
|
||||
|
||||
|
||||
class SAMLConfig(BaseModel):
|
||||
enabled: bool = False
|
||||
entity_id: str
|
||||
acs_url: str
|
||||
idp_metadata: str = ""
|
||||
sp_key_file: Optional[str] = None
|
||||
sp_cert_file: Optional[str] = None
|
||||
allow_unsolicited: bool = False
|
||||
xmlsec_binary: Optional[str] = None
|
||||
attribute_map: Dict[str, str] = Field(
|
||||
default_factory=lambda: dict(DEFAULT_SAML_ATTRIBUTE_MAP)
|
||||
)
|
||||
|
||||
@model_validator(mode="after")
|
||||
def _require_idp_metadata(self) -> "SAMLConfig":
|
||||
if self.enabled and not self.idp_metadata.strip():
|
||||
raise ValueError(
|
||||
"SAML enabled but idp_metadata is empty (inline XML, local path, or URL)"
|
||||
)
|
||||
return self
|
||||
|
|
@ -13,11 +13,11 @@ from scim2_models import Email, Name
|
|||
from scim2_models import User as ScimUser
|
||||
|
||||
from .config import SAMLConfig
|
||||
from .resolver import ProvisioningStore
|
||||
from .session import safe_relay_state
|
||||
from ..resolver import ProvisioningStore
|
||||
from ..session import safe_relay_state
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .security import AuthSecurity
|
||||
from ..security import AuthSecurity
|
||||
|
||||
_SINGLE_VALUE_TARGETS = {
|
||||
"email",
|
||||
3
litellm/proxy/auth_v2/scim/__init__.py
Normal file
3
litellm/proxy/auth_v2/scim/__init__.py
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
from .router import build_scim_router
|
||||
|
||||
__all__ = ["build_scim_router"]
|
||||
|
|
@ -23,10 +23,10 @@ from scim2_models import (
|
|||
User,
|
||||
)
|
||||
|
||||
from .resolver import ProvisioningStore
|
||||
from ..resolver import ProvisioningStore
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .security import AuthSecurity
|
||||
from ..security import AuthSecurity
|
||||
|
||||
R = TypeVar("R", bound=Resource)
|
||||
|
||||
|
|
@ -5,10 +5,21 @@ import time
|
|||
from typing import Any, Dict, Optional, Tuple
|
||||
|
||||
from fastapi import Request
|
||||
from pydantic import BaseModel
|
||||
|
||||
from .models import AuthMethod, Credential, CredentialRef, SecuritySchemeType
|
||||
|
||||
|
||||
class SessionConfig(BaseModel):
|
||||
cookie: str = "litellm_session"
|
||||
secure: bool = True
|
||||
ttl_seconds: int = 3600
|
||||
max_size: int = 10000
|
||||
default_redirect_path: str = "/"
|
||||
login_cookie: str = "litellm_oidc_txn"
|
||||
login_state_ttl: int = 300
|
||||
|
||||
|
||||
def safe_relay_state(target: Optional[str], default: str) -> str:
|
||||
if (
|
||||
target
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue