diff --git a/app/api/internal.py b/app/api/internal.py index 411f67e..e5e4f8b 100644 --- a/app/api/internal.py +++ b/app/api/internal.py @@ -1,4 +1,4 @@ -from fastapi import APIRouter, Depends, Header, HTTPException, status +from fastapi import APIRouter, Depends, HTTPException, status from sqlalchemy.orm import Session from app.core.config import get_settings @@ -8,24 +8,16 @@ from app.repositories.users_repo import UsersRepository from app.schemas.authentik_admin import AuthentikEnsureUserRequest, AuthentikEnsureUserResponse from app.schemas.permissions import PermissionSnapshotResponse from app.schemas.users import UserUpsertBySubRequest +from app.security.api_client_auth import require_api_client from app.services.authentik_admin_service import AuthentikAdminService from app.services.permission_service import PermissionService -router = APIRouter(prefix="/internal", tags=["internal"]) - - -def verify_internal_secret(x_internal_secret: str = Header(alias="X-Internal-Secret")) -> None: - settings = get_settings() - if not settings.internal_shared_secret: - raise HTTPException(status_code=status.HTTP_503_SERVICE_UNAVAILABLE, detail="internal_secret_not_configured") - if x_internal_secret != settings.internal_shared_secret: - raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="invalid_internal_secret") +router = APIRouter(prefix="/internal", tags=["internal"], dependencies=[Depends(require_api_client)]) @router.post("/users/upsert-by-sub") def upsert_user_by_sub( payload: UserUpsertBySubRequest, - _: None = Depends(verify_internal_secret), db: Session = Depends(get_db), ) -> dict[str, str | bool | None]: repo = UsersRepository(db) @@ -50,7 +42,6 @@ def upsert_user_by_sub( @router.get("/permissions/{authentik_sub}/snapshot", response_model=PermissionSnapshotResponse) def get_permission_snapshot( authentik_sub: str, - _: None = Depends(verify_internal_secret), db: Session = Depends(get_db), ) -> PermissionSnapshotResponse: users_repo = UsersRepository(db) @@ -67,7 +58,6 @@ def get_permission_snapshot( @router.post("/authentik/users/ensure", response_model=AuthentikEnsureUserResponse) def ensure_authentik_user( payload: AuthentikEnsureUserRequest, - _: None = Depends(verify_internal_secret), db: Session = Depends(get_db), ) -> AuthentikEnsureUserResponse: settings = get_settings() diff --git a/app/api/internal_catalog.py b/app/api/internal_catalog.py index 6c05269..abf4ad4 100644 --- a/app/api/internal_catalog.py +++ b/app/api/internal_catalog.py @@ -1,20 +1,19 @@ from fastapi import APIRouter, Depends, Query from sqlalchemy.orm import Session -from app.api.internal import verify_internal_secret from app.db.session import get_db from app.repositories.companies_repo import CompaniesRepository from app.repositories.modules_repo import ModulesRepository from app.repositories.sites_repo import SitesRepository from app.repositories.systems_repo import SystemsRepository from app.repositories.users_repo import UsersRepository +from app.security.api_client_auth import require_api_client -router = APIRouter(prefix="/internal", tags=["internal"]) +router = APIRouter(prefix="/internal", tags=["internal"], dependencies=[Depends(require_api_client)]) @router.get("/systems") def internal_list_systems( - _: None = Depends(verify_internal_secret), db: Session = Depends(get_db), limit: int = Query(default=200, ge=1, le=1000), offset: int = Query(default=0, ge=0), @@ -26,7 +25,6 @@ def internal_list_systems( @router.get("/modules") def internal_list_modules( - _: None = Depends(verify_internal_secret), db: Session = Depends(get_db), limit: int = Query(default=500, ge=1, le=2000), offset: int = Query(default=0, ge=0), @@ -52,7 +50,6 @@ def internal_list_modules( @router.get("/companies") def internal_list_companies( - _: None = Depends(verify_internal_secret), db: Session = Depends(get_db), keyword: str | None = Query(default=None), limit: int = Query(default=500, ge=1, le=2000), @@ -65,7 +62,6 @@ def internal_list_companies( @router.get("/sites") def internal_list_sites( - _: None = Depends(verify_internal_secret), db: Session = Depends(get_db), company_key: str | None = Query(default=None), limit: int = Query(default=500, ge=1, le=2000), @@ -86,7 +82,6 @@ def internal_list_sites( @router.get("/members") def internal_list_members( - _: None = Depends(verify_internal_secret), db: Session = Depends(get_db), keyword: str | None = Query(default=None), limit: int = Query(default=500, ge=1, le=2000), diff --git a/tests/test_internal_authentik_sync.py b/tests/test_internal_authentik_sync.py index 8ea80a7..a48d522 100644 --- a/tests/test_internal_authentik_sync.py +++ b/tests/test_internal_authentik_sync.py @@ -1,19 +1,23 @@ from fastapi.testclient import TestClient from app.main import app +from app.security.api_client_auth import require_api_client def test_internal_authentik_ensure_requires_config() -> None: + app.dependency_overrides[require_api_client] = lambda: None client = TestClient(app) - resp = client.post( - "/internal/authentik/users/ensure", - headers={"X-Internal-Secret": "CHANGE_ME"}, - json={ - "sub": "authentik-sub-1", - "email": "user@example.com", - "display_name": "User Example", - "is_active": True, - }, - ) - assert resp.status_code == 503 - assert resp.json()["detail"] == "authentik_admin_not_configured" + try: + resp = client.post( + "/internal/authentik/users/ensure", + json={ + "sub": "authentik-sub-1", + "email": "user@example.com", + "display_name": "User Example", + "is_active": True, + }, + ) + assert resp.status_code == 503 + assert resp.json()["detail"] == "authentik_admin_not_configured" + finally: + app.dependency_overrides.pop(require_api_client, None)