Update
This commit is contained in:
+106
-23
@@ -2,30 +2,71 @@ from __future__ import annotations
|
||||
|
||||
from datetime import UTC, datetime
|
||||
|
||||
from fastapi import APIRouter, Request, Response, status
|
||||
from fastapi import APIRouter, Depends, Request, Response, status
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from app.core.config import get_settings
|
||||
from app.core.errors import AppError
|
||||
from app.db.session import get_db
|
||||
from app.schemas.auth import AuthLoginRequest, AuthSession, AuthSessionEnvelope
|
||||
from app.services.auth_service import AuthService
|
||||
from app.services.auth_service import AuthPrincipal, AuthService
|
||||
from app.services.demo_workflow_service import DemoWorkflowService
|
||||
|
||||
|
||||
router = APIRouter(prefix="/auth", tags=["auth"])
|
||||
COOKIE_NAME = "geointel_session"
|
||||
|
||||
|
||||
def _session_payload(request: Request) -> AuthSession:
|
||||
settings = get_settings()
|
||||
if not settings.auth_enabled:
|
||||
return AuthSession(authentication_required=False, authenticated=True)
|
||||
principal = AuthService.verify_session_token(request.cookies.get(COOKIE_NAME), settings)
|
||||
if principal is None:
|
||||
return AuthSession(authentication_required=True, authenticated=False)
|
||||
def _session_from_principal(principal: AuthPrincipal, *, guest_access_enabled: bool) -> AuthSession:
|
||||
return AuthSession(
|
||||
authentication_required=True,
|
||||
authenticated=True,
|
||||
username=principal.username,
|
||||
expires_at=datetime.fromtimestamp(principal.expires_at, tz=UTC),
|
||||
role=principal.role,
|
||||
guest_access_enabled=guest_access_enabled,
|
||||
guest_project_id=principal.project_id,
|
||||
)
|
||||
|
||||
|
||||
def _session_payload(request: Request) -> AuthSession:
|
||||
settings = get_settings()
|
||||
guest_access_enabled = settings.auth_enabled and settings.guest_access_enabled
|
||||
if not settings.auth_enabled:
|
||||
return AuthSession(
|
||||
authentication_required=False,
|
||||
authenticated=True,
|
||||
guest_access_enabled=False,
|
||||
)
|
||||
principal = AuthService.verify_session_token(request.cookies.get(COOKIE_NAME), settings)
|
||||
if principal is None:
|
||||
return AuthSession(
|
||||
authentication_required=True,
|
||||
authenticated=False,
|
||||
guest_access_enabled=guest_access_enabled,
|
||||
)
|
||||
return _session_from_principal(
|
||||
principal,
|
||||
guest_access_enabled=guest_access_enabled,
|
||||
)
|
||||
|
||||
|
||||
def _set_session_cookie(
|
||||
*,
|
||||
request: Request,
|
||||
response: Response,
|
||||
token: str,
|
||||
max_age: int,
|
||||
) -> None:
|
||||
forwarded_proto = request.headers.get("x-forwarded-proto", "").split(",", 1)[0].strip().lower()
|
||||
response.set_cookie(
|
||||
key=COOKIE_NAME,
|
||||
value=token,
|
||||
max_age=max_age,
|
||||
httponly=True,
|
||||
secure=forwarded_proto == "https" or request.url.scheme == "https",
|
||||
samesite="strict",
|
||||
path="/",
|
||||
)
|
||||
|
||||
|
||||
@@ -69,29 +110,71 @@ def login(payload: AuthLoginRequest, request: Request, response: Response) -> Au
|
||||
message="De beveiligde sessie kon niet worden aangemaakt.",
|
||||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||
)
|
||||
forwarded_proto = request.headers.get("x-forwarded-proto", "").split(",", 1)[0].strip().lower()
|
||||
response.set_cookie(
|
||||
key=COOKIE_NAME,
|
||||
value=token,
|
||||
_set_session_cookie(
|
||||
request=request,
|
||||
response=response,
|
||||
token=token,
|
||||
max_age=settings.auth_session_ttl_seconds,
|
||||
httponly=True,
|
||||
secure=forwarded_proto == "https" or request.url.scheme == "https",
|
||||
samesite="strict",
|
||||
path="/",
|
||||
)
|
||||
return AuthSessionEnvelope(
|
||||
data=AuthSession(
|
||||
authentication_required=True,
|
||||
authenticated=True,
|
||||
username=principal.username,
|
||||
expires_at=datetime.fromtimestamp(principal.expires_at, tz=UTC),
|
||||
data=_session_from_principal(
|
||||
principal,
|
||||
guest_access_enabled=settings.guest_access_enabled,
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
@router.post("/guest", response_model=AuthSessionEnvelope)
|
||||
def guest_login(
|
||||
request: Request,
|
||||
response: Response,
|
||||
db: Session = Depends(get_db),
|
||||
) -> AuthSessionEnvelope:
|
||||
settings = get_settings()
|
||||
if not settings.auth_enabled or not settings.guest_access_enabled:
|
||||
raise AppError(
|
||||
code="GUEST_ACCESS_DISABLED",
|
||||
message="Gasttoegang is niet ingeschakeld op deze GeoIntel-installatie.",
|
||||
status_code=status.HTTP_403_FORBIDDEN,
|
||||
)
|
||||
|
||||
demo = DemoWorkflowService.seed(db)
|
||||
token = AuthService.create_session_token(
|
||||
settings.guest_display_name,
|
||||
settings,
|
||||
role="guest",
|
||||
project_id=demo.project_id,
|
||||
ttl_seconds=settings.guest_session_ttl_seconds,
|
||||
)
|
||||
principal = AuthService.verify_session_token(token, settings)
|
||||
if principal is None: # pragma: no cover - defensive invariant
|
||||
raise AppError(
|
||||
code="SESSION_CREATION_FAILED",
|
||||
message="De tijdelijke gastensessie kon niet worden aangemaakt.",
|
||||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||
)
|
||||
_set_session_cookie(
|
||||
request=request,
|
||||
response=response,
|
||||
token=token,
|
||||
max_age=settings.guest_session_ttl_seconds,
|
||||
)
|
||||
return AuthSessionEnvelope(
|
||||
data=_session_from_principal(
|
||||
principal,
|
||||
guest_access_enabled=True,
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
@router.post("/logout", response_model=AuthSessionEnvelope)
|
||||
def logout(response: Response) -> AuthSessionEnvelope:
|
||||
settings = get_settings()
|
||||
response.delete_cookie(key=COOKIE_NAME, path="/", httponly=True, samesite="strict")
|
||||
return AuthSessionEnvelope(
|
||||
data=AuthSession(authentication_required=True, authenticated=False)
|
||||
data=AuthSession(
|
||||
authentication_required=settings.auth_enabled,
|
||||
authenticated=not settings.auth_enabled,
|
||||
guest_access_enabled=settings.auth_enabled and settings.guest_access_enabled,
|
||||
)
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user