mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-13 23:11:40 +00:00
refactor(proxy): group auth_v2 into authn/authz/stages subpackages
Pure move (git mv, history preserved): the flat 17-file package hid the architecture behind an alphabetical wall. Group by request phase so the module is self-documenting: authn/ authenticators, jwt_claims, jwt_verifier, oauth2_introspection authz/ enforcer + model.conf, authorizer, route_map, policy_store, policy_admin stages/ enrichment, end_user, budgets (top) entry, context, principal, management_endpoints, __init__ No content changes beyond rewired relative imports; tests moved to mirror the layout. Behavior is identical — the same 129 tests pass, mypy/black/ruff clean, and the package still imports with casbin/authlib absent.
This commit is contained in:
parent
c7f1215bad
commit
764ffd834e
33 changed files with 33 additions and 33 deletions
|
|
@ -45,13 +45,13 @@ independent of v1/v2.
|
|||
JWT, and OAuth authenticators return a thin identity (no budget/limit fields), so
|
||||
the hooks read `None` and enforce nothing for those logins.
|
||||
|
||||
**Built.** `enrichment.py` (`enrich_identity`) copies the user/team limit fields
|
||||
**Built.** `stages/enrichment.py` (`enrich_identity`) copies the user/team limit fields
|
||||
1:1 from the rows into the identity's distinct `user_*` / `team_*` slots, filling
|
||||
only unset fields so it never overrides an already-resolved value. It is wired
|
||||
into the inference path in `entry.py` for non-virtual-key logins
|
||||
(`_enrich_for_limits`), with the loaders (`get_user_object` auth_checks.py:1650,
|
||||
`get_team_object` auth_checks.py:1982) injected. Unit-tested in
|
||||
`test_enrichment.py`.
|
||||
`stages/test_enrichment.py`.
|
||||
|
||||
**What remains (live).** Only the verification below. The mapping is additive
|
||||
(these logins enforce nothing today, so it cannot regress existing behavior), but
|
||||
|
|
@ -74,12 +74,12 @@ limit silently over- or under-enforces a customer's spend.
|
|||
|
||||
**Done.** Team, organization, and global proxy-spend caps live in v1's
|
||||
`common_checks`, which v2 does not run. Rather than move them (which would risk
|
||||
v1's path), `budgets.py` (`enforce_hierarchy_budgets`) calls the *same* functions
|
||||
v1's path), `stages/budgets.py` (`enforce_hierarchy_budgets`) calls the *same* functions
|
||||
v1 uses — `_team_max_budget_check`, `_organization_max_budget_check`, and
|
||||
`get_global_proxy_spend` + `_global_proxy_budget_check` — from v2's inference
|
||||
path. One implementation, two callers: single authority, correct counter keys, no
|
||||
edit to v1. A breach surfaces as the same 429 `ProxyException` v1 raises.
|
||||
Unit-tested in `test_budgets.py` (team over/under budget, no-team no-op).
|
||||
Unit-tested in `stages/test_budgets.py` (team over/under budget, no-team no-op).
|
||||
|
||||
**What remains (live).** Cross-pod spend-counter accuracy. Set a team `max_budget`
|
||||
(and `litellm.max_budget` for the global cap) below current spend and confirm
|
||||
|
|
|
|||
|
|
@ -6,9 +6,9 @@ from .context import (
|
|||
set_auth_context,
|
||||
try_get_auth_context,
|
||||
)
|
||||
from .end_user import resolve_end_user
|
||||
from .enrichment import enrich_identity
|
||||
from .entry import user_api_key_auth_v2
|
||||
from .stages.end_user import resolve_end_user
|
||||
from .stages.enrichment import enrich_identity
|
||||
|
||||
__all__ = [
|
||||
"user_api_key_auth_v2",
|
||||
|
|
|
|||
0
litellm/proxy/auth/v2/authn/__init__.py
Normal file
0
litellm/proxy/auth/v2/authn/__init__.py
Normal file
|
|
@ -4,7 +4,7 @@ from typing import TYPE_CHECKING, Any, List, Optional, Protocol, runtime_checkab
|
|||
|
||||
from fastapi import HTTPException, status
|
||||
|
||||
from .context import AuthMethod
|
||||
from ..context import AuthMethod
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from litellm.proxy._types import UserAPIKeyAuth
|
||||
0
litellm/proxy/auth/v2/authz/__init__.py
Normal file
0
litellm/proxy/auth/v2/authz/__init__.py
Normal file
|
|
@ -1,7 +1,7 @@
|
|||
import logging
|
||||
from typing import Any, Dict, Optional
|
||||
|
||||
from .principal import Principal
|
||||
from ..principal import Principal
|
||||
from .route_map import GovernedRoute, match_route
|
||||
|
||||
logger = logging.getLogger("litellm.proxy.auth.v2")
|
||||
|
|
@ -4,16 +4,16 @@ from fastapi import HTTPException, Request, status
|
|||
|
||||
from litellm.integrations.otel.runtime import seed_request_identity
|
||||
|
||||
from .authenticators import AuthContext, AuthResult, authenticate
|
||||
from .authorizer import AuthorizationDenied, authorize
|
||||
from .budgets import enforce_hierarchy_budgets
|
||||
from .authn.authenticators import AuthContext, AuthResult, authenticate
|
||||
from .authz.authorizer import AuthorizationDenied, authorize
|
||||
from .authz.enforcer import CasbinEnforcer
|
||||
from .authz.policy_store import load_policy_snapshot
|
||||
from .authz.route_map import is_inference_route, match_route
|
||||
from .context import AuthMethod, RequestAuthContext, set_auth_context
|
||||
from .end_user import resolve_end_user
|
||||
from .enforcer import CasbinEnforcer
|
||||
from .enrichment import enrich_identity
|
||||
from .policy_store import load_policy_snapshot
|
||||
from .principal import Principal, build_principal
|
||||
from .route_map import is_inference_route, match_route
|
||||
from .stages.budgets import enforce_hierarchy_budgets
|
||||
from .stages.end_user import resolve_end_user
|
||||
from .stages.enrichment import enrich_identity
|
||||
|
||||
|
||||
async def _anonymous_identity(api_key: Optional[str]) -> Any:
|
||||
|
|
|
|||
|
|
@ -6,12 +6,12 @@ from pydantic import BaseModel
|
|||
from litellm.proxy._types import LitellmUserRoles, UserAPIKeyAuth
|
||||
from litellm.proxy.auth.user_api_key_auth import user_api_key_auth
|
||||
|
||||
from .policy_admin import (
|
||||
from .authz.policy_admin import (
|
||||
PolicyValidationError,
|
||||
make_assignment_rule,
|
||||
make_permission_rule,
|
||||
)
|
||||
from .policy_store import reset_cache
|
||||
from .authz.policy_store import reset_cache
|
||||
|
||||
router = APIRouter(tags=["auth_v2"])
|
||||
|
||||
|
|
|
|||
0
litellm/proxy/auth/v2/stages/__init__.py
Normal file
0
litellm/proxy/auth/v2/stages/__init__.py
Normal file
|
|
@ -2,7 +2,7 @@ from typing import Awaitable, Callable, Optional
|
|||
|
||||
from starlette.requests import Request
|
||||
|
||||
from .context import attach_end_user
|
||||
from ..context import attach_end_user
|
||||
|
||||
# Extraction reuses the existing request-body/header logic; validation (the
|
||||
# customer-table lookup) is injected so this stage is testable without a DB and
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
import pytest
|
||||
|
||||
from litellm.proxy.auth.v2.authenticators import (
|
||||
from litellm.proxy.auth.v2.authn.authenticators import (
|
||||
OAuth2IntrospectionAuthenticator,
|
||||
JWTAuthenticator,
|
||||
MasterKeyAuthenticator,
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
import pytest
|
||||
|
||||
from litellm.proxy.auth.v2.jwt_claims import (
|
||||
from litellm.proxy.auth.v2.authn.jwt_claims import (
|
||||
JWTClaimError,
|
||||
JWTSettings,
|
||||
extract_identity,
|
||||
|
|
@ -3,7 +3,7 @@ import time
|
|||
import pytest
|
||||
from authlib.jose import JsonWebKey, jwt
|
||||
|
||||
from litellm.proxy.auth.v2.jwt_verifier import JWTVerificationError, verify
|
||||
from litellm.proxy.auth.v2.authn.jwt_verifier import JWTVerificationError, verify
|
||||
|
||||
ISSUER = "https://idp.example"
|
||||
AUDIENCE = "litellm"
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
import pytest
|
||||
|
||||
from litellm.proxy.auth.v2.oauth2_introspection import (
|
||||
from litellm.proxy.auth.v2.authn.oauth2_introspection import (
|
||||
IntrospectionSettings,
|
||||
OAuth2IntrospectionError,
|
||||
parse_introspection_response,
|
||||
|
|
@ -2,7 +2,7 @@ import logging
|
|||
|
||||
import pytest
|
||||
|
||||
from litellm.proxy.auth.v2.authorizer import AuthorizationDenied, authorize
|
||||
from litellm.proxy.auth.v2.authz.authorizer import AuthorizationDenied, authorize
|
||||
from litellm.proxy.auth.v2.principal import Principal
|
||||
|
||||
PRINCIPAL = Principal(subject="user:u1", domain="*", groupings=[])
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
from litellm.proxy.auth.v2.enforcer import CasbinEnforcer
|
||||
from litellm.proxy.auth.v2.authz.enforcer import CasbinEnforcer
|
||||
|
||||
READER_POLICY = ["role:model_reader", "*", "model:*", "read", "allow"]
|
||||
ADMIN_POLICY = ["role:proxy_admin", "*", "*", "*", "allow"]
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
import pytest
|
||||
|
||||
from litellm.proxy.auth.v2.policy_admin import (
|
||||
from litellm.proxy.auth.v2.authz.policy_admin import (
|
||||
PolicyValidationError,
|
||||
make_assignment_rule,
|
||||
make_permission_rule,
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
import pytest
|
||||
|
||||
from litellm.proxy.auth.v2 import policy_store
|
||||
from litellm.proxy.auth.v2.policy_store import (
|
||||
from litellm.proxy.auth.v2.authz import policy_store
|
||||
from litellm.proxy.auth.v2.authz.policy_store import (
|
||||
DEFAULT_POLICIES,
|
||||
load_policy_snapshot,
|
||||
reset_cache,
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
from litellm.proxy.auth.v2.route_map import is_inference_route, match_route
|
||||
from litellm.proxy.auth.v2.authz.route_map import is_inference_route, match_route
|
||||
|
||||
|
||||
def test_model_routes_map_to_resource_and_action():
|
||||
|
|
@ -12,7 +12,7 @@ import pytest
|
|||
|
||||
import litellm
|
||||
from litellm.proxy._types import UserAPIKeyAuth
|
||||
from litellm.proxy.auth.v2.budgets import enforce_hierarchy_budgets
|
||||
from litellm.proxy.auth.v2.stages.budgets import enforce_hierarchy_budgets
|
||||
|
||||
|
||||
class _Logging:
|
||||
|
|
@ -8,7 +8,7 @@ from litellm.proxy.auth.v2.context import (
|
|||
get_auth_context,
|
||||
set_auth_context,
|
||||
)
|
||||
from litellm.proxy.auth.v2.end_user import resolve_end_user
|
||||
from litellm.proxy.auth.v2.stages.end_user import resolve_end_user
|
||||
from litellm.proxy.auth.v2.principal import Principal
|
||||
|
||||
|
||||
|
|
@ -2,7 +2,7 @@ from types import SimpleNamespace
|
|||
|
||||
import pytest
|
||||
|
||||
from litellm.proxy.auth.v2.enrichment import enrich_identity
|
||||
from litellm.proxy.auth.v2.stages.enrichment import enrich_identity
|
||||
|
||||
|
||||
def _identity(**overrides):
|
||||
|
|
@ -13,7 +13,7 @@ from fastapi.testclient import TestClient
|
|||
import litellm.proxy.proxy_server as ps
|
||||
from litellm.proxy._types import UserAPIKeyAuth
|
||||
from litellm.proxy.auth.user_api_key_auth import user_api_key_auth
|
||||
from litellm.proxy.auth.v2 import policy_store
|
||||
from litellm.proxy.auth.v2.authz import policy_store
|
||||
from litellm.proxy.auth.v2.management_endpoints import router as auth_v2_router
|
||||
|
||||
MASTER_KEY = "sk-master-1234"
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue