Updates
This commit is contained in:
@@ -16,18 +16,16 @@ from __future__ import annotations
|
||||
|
||||
from typing import Iterable
|
||||
|
||||
from fastapi import Depends, HTTPException, status
|
||||
from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer
|
||||
from fastapi import Depends, HTTPException, Request, status
|
||||
from sqlalchemy import select
|
||||
from sqlalchemy.orm import Session, selectinload
|
||||
|
||||
from app.core.security import verify_token
|
||||
from app.core.http import CLIENT_AUTH_COOKIE, get_bearer_or_cookie_token
|
||||
from app.core.security_logging import log_security_event
|
||||
from app.db.session import get_db
|
||||
from app.models.access import Permission, Role, User
|
||||
|
||||
|
||||
bearer_scheme = HTTPBearer(auto_error=False)
|
||||
|
||||
# Subject claim used by tokens issued for internal Hunter Stock Feeds users.
|
||||
# Distinct from the existing client-portal/admin tokens so the two systems
|
||||
# cannot impersonate each other.
|
||||
@@ -103,7 +101,7 @@ def _load_user(db: Session, user_id: int) -> User | None:
|
||||
|
||||
|
||||
def get_current_user(
|
||||
credentials: HTTPAuthorizationCredentials | None = Depends(bearer_scheme),
|
||||
request: Request,
|
||||
db: Session = Depends(get_db),
|
||||
) -> User:
|
||||
"""Resolve the current internal user from the bearer token.
|
||||
@@ -111,10 +109,11 @@ def get_current_user(
|
||||
Raises 401 for missing/invalid tokens or unknown users, 403 for inactive
|
||||
users.
|
||||
"""
|
||||
if credentials is None:
|
||||
token = get_bearer_or_cookie_token(request, cookie_name=CLIENT_AUTH_COOKIE.name)
|
||||
if token is None:
|
||||
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Authentication required")
|
||||
|
||||
payload = verify_token(credentials.credentials)
|
||||
payload = verify_token(token)
|
||||
if payload.get("sub") != INTERNAL_USER_SUBJECT:
|
||||
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid authentication token")
|
||||
|
||||
@@ -136,6 +135,7 @@ def require_permission(permission_key: str):
|
||||
|
||||
def dependency(user: User = Depends(get_current_user)) -> User:
|
||||
if not user_has_permission(user, permission_key):
|
||||
log_security_event("authz.denied", role=user.role.name if user.role else None, permission=permission_key)
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_403_FORBIDDEN,
|
||||
detail=f"Missing required permission: {permission_key}",
|
||||
@@ -152,6 +152,7 @@ def require_any_permission(permission_keys: Iterable[str]):
|
||||
def dependency(user: User = Depends(get_current_user)) -> User:
|
||||
granted = get_user_permissions(user)
|
||||
if not any(key in granted for key in keys):
|
||||
log_security_event("authz.denied", role=user.role.name if user.role else None, permissions=list(keys))
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_403_FORBIDDEN,
|
||||
detail=f"Requires any of: {list(keys)}",
|
||||
@@ -169,6 +170,7 @@ def require_all_permissions(permission_keys: Iterable[str]):
|
||||
granted = get_user_permissions(user)
|
||||
missing = [key for key in keys if key not in granted]
|
||||
if missing:
|
||||
log_security_event("authz.denied", role=user.role.name if user.role else None, permissions=missing)
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_403_FORBIDDEN,
|
||||
detail=f"Missing required permissions: {missing}",
|
||||
|
||||
Reference in New Issue
Block a user