-
-
Notifications
You must be signed in to change notification settings - Fork 7
Expand file tree
/
Copy pathplatform_admin.py
More file actions
149 lines (122 loc) 路 4.62 KB
/
Copy pathplatform_admin.py
File metadata and controls
149 lines (122 loc) 路 4.62 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
"""Platform admin JWT issuance and FastAPI dependencies."""
from __future__ import annotations
from dataclasses import dataclass
from datetime import datetime, timedelta, timezone
from typing import Any, Dict, Optional, Tuple
from uuid import UUID, uuid4
from fastapi import Depends, Header, HTTPException, status
from jose import JWTError, jwt
from sqlalchemy.orm import Session
from app.config import settings
from app.core.auth.token_revocation import is_access_jti_revoked, revoke_access_jti
from app.database import get_db
from app.models.database import PlatformAdmin
PLATFORM_ISSUER = "efficientai-platform"
PLATFORM_SCOPE = "platform_admin"
ALGORITHM = "HS256"
@dataclass(frozen=True)
class PlatformAdminPrincipal:
platform_admin_id: UUID
email: str
def create_platform_access_token(
*,
platform_admin_id: UUID,
email: str,
expires_in_minutes: Optional[int] = None,
) -> Tuple[str, int]:
ttl_minutes = expires_in_minutes or getattr(settings, "AUTH_LOCAL_TOKEN_TTL_MINUTES", 15)
ttl_seconds = ttl_minutes * 60
now = datetime.now(timezone.utc)
payload: Dict[str, Any] = {
"iss": PLATFORM_ISSUER,
"sub": str(platform_admin_id),
"email": email,
"scope": PLATFORM_SCOPE,
"jti": str(uuid4()),
"iat": int(now.timestamp()),
"exp": int((now + timedelta(minutes=ttl_minutes)).timestamp()),
}
token = jwt.encode(payload, settings.SECRET_KEY, algorithm=ALGORITHM)
return token, ttl_seconds
def decode_platform_access_token(token: str) -> Dict[str, Any]:
return jwt.decode(
token,
settings.SECRET_KEY,
algorithms=[ALGORITHM],
issuer=PLATFORM_ISSUER,
options={"verify_aud": False},
)
def revoke_platform_access_token(token: str) -> None:
try:
claims = decode_platform_access_token(token)
jti = claims.get("jti")
exp = claims.get("exp")
if jti and exp:
ttl = max(int(exp) - int(datetime.now(timezone.utc).timestamp()), 1)
revoke_access_jti(jti, ttl)
except JWTError:
pass
def _extract_bearer(authorization: Optional[str]) -> Optional[str]:
if not authorization:
return None
scheme, _, token = authorization.partition(" ")
if scheme.lower() != "bearer" or not token.strip():
return None
return token.strip()
def platform_admin_feature_enabled(db: Session) -> bool:
return (
db.query(PlatformAdmin.id)
.filter(PlatformAdmin.is_active == True) # noqa: E712
.first()
is not None
)
def require_platform_admin_feature(db: Session = Depends(get_db)) -> None:
if not platform_admin_feature_enabled(db):
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Not found")
def get_platform_admin(
authorization: Optional[str] = Header(None, alias="Authorization"),
db: Session = Depends(get_db),
_feature: None = Depends(require_platform_admin_feature),
) -> PlatformAdminPrincipal:
bearer = _extract_bearer(authorization)
if not bearer:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Authentication required (send Authorization: Bearer ...)",
)
try:
claims = decode_platform_access_token(bearer)
except JWTError as exc:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail=f"Invalid platform admin token: {exc}",
) from exc
if claims.get("scope") != PLATFORM_SCOPE:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Invalid platform admin token scope.",
)
jti = claims.get("jti")
if jti and is_access_jti_revoked(jti):
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Token has been revoked.",
)
try:
admin_id = UUID(claims["sub"])
except (KeyError, ValueError) as exc:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Malformed platform admin token.",
) from exc
admin = (
db.query(PlatformAdmin)
.filter(PlatformAdmin.id == admin_id, PlatformAdmin.is_active == True) # noqa: E712
.first()
)
if admin is None:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Platform admin no longer active.",
)
return PlatformAdminPrincipal(platform_admin_id=admin.id, email=admin.email)