Harden auth and security controls with session auth and docs
This commit is contained in:
@@ -272,10 +272,10 @@ if "app.services.routing_pipeline" not in sys.modules:
|
||||
sys.modules["app.services.routing_pipeline"] = routing_pipeline_stub
|
||||
|
||||
from fastapi import HTTPException
|
||||
from fastapi.security import HTTPAuthorizationCredentials
|
||||
|
||||
from app.api.auth import AuthRole, get_request_role, require_admin
|
||||
from app.api.auth import AuthContext, require_admin
|
||||
from app.core import config as config_module
|
||||
from app.models.auth import UserRole
|
||||
from app.models.processing_log import sanitize_processing_log_payload_value, sanitize_processing_log_text
|
||||
from app.schemas.processing_logs import ProcessingLogEntryResponse
|
||||
from app.services import extractor as extractor_module
|
||||
@@ -298,52 +298,34 @@ def _security_settings(
|
||||
|
||||
|
||||
class AuthDependencyTests(unittest.TestCase):
|
||||
"""Verifies token authentication and admin authorization behavior."""
|
||||
|
||||
def test_get_request_role_accepts_admin_token(self) -> None:
|
||||
"""Admin token resolves admin role."""
|
||||
|
||||
settings = SimpleNamespace(
|
||||
admin_api_token="admin-token",
|
||||
user_api_token="user-token",
|
||||
allow_development_anonymous_user_access=False,
|
||||
app_env="production",
|
||||
)
|
||||
credentials = HTTPAuthorizationCredentials(scheme="Bearer", credentials="admin-token")
|
||||
role = get_request_role(credentials=credentials, settings=settings)
|
||||
self.assertEqual(role, AuthRole.ADMIN)
|
||||
|
||||
def test_get_request_role_rejects_missing_credentials(self) -> None:
|
||||
"""Missing bearer credentials return 401."""
|
||||
|
||||
settings = SimpleNamespace(
|
||||
admin_api_token="admin-token",
|
||||
user_api_token="user-token",
|
||||
allow_development_anonymous_user_access=False,
|
||||
app_env="production",
|
||||
)
|
||||
with self.assertRaises(HTTPException) as context:
|
||||
get_request_role(credentials=None, settings=settings)
|
||||
self.assertEqual(context.exception.status_code, 401)
|
||||
|
||||
def test_get_request_role_allows_tokenless_user_access_in_development(self) -> None:
|
||||
"""Development mode can allow tokenless user role for compatibility."""
|
||||
|
||||
settings = SimpleNamespace(
|
||||
admin_api_token="admin-token",
|
||||
user_api_token="user-token",
|
||||
allow_development_anonymous_user_access=True,
|
||||
app_env="development",
|
||||
)
|
||||
role = get_request_role(credentials=None, settings=settings)
|
||||
self.assertEqual(role, AuthRole.USER)
|
||||
"""Verifies role-based admin authorization behavior."""
|
||||
|
||||
def test_require_admin_rejects_user_role(self) -> None:
|
||||
"""User role cannot access admin-only endpoints."""
|
||||
|
||||
with self.assertRaises(HTTPException) as context:
|
||||
require_admin(role=AuthRole.USER)
|
||||
self.assertEqual(context.exception.status_code, 403)
|
||||
auth_context = AuthContext(
|
||||
user_id=uuid.uuid4(),
|
||||
username="user",
|
||||
role=UserRole.USER,
|
||||
session_id=uuid.uuid4(),
|
||||
expires_at=datetime.now(UTC),
|
||||
)
|
||||
with self.assertRaises(HTTPException) as raised:
|
||||
require_admin(context=auth_context)
|
||||
self.assertEqual(raised.exception.status_code, 403)
|
||||
|
||||
def test_require_admin_accepts_admin_role(self) -> None:
|
||||
"""Admin role is accepted for admin-only endpoints."""
|
||||
|
||||
auth_context = AuthContext(
|
||||
user_id=uuid.uuid4(),
|
||||
username="admin",
|
||||
role=UserRole.ADMIN,
|
||||
session_id=uuid.uuid4(),
|
||||
expires_at=datetime.now(UTC),
|
||||
)
|
||||
resolved = require_admin(context=auth_context)
|
||||
self.assertEqual(resolved.role, UserRole.ADMIN)
|
||||
|
||||
|
||||
class ProviderBaseUrlValidationTests(unittest.TestCase):
|
||||
@@ -559,6 +541,7 @@ class ArchiveLineagePropagationTests(unittest.TestCase):
|
||||
source_relative_path="uploads/root.zip",
|
||||
logical_path="Inbox",
|
||||
tags=["finance"],
|
||||
owner_user_id=uuid.uuid4(),
|
||||
)
|
||||
|
||||
with (
|
||||
@@ -578,6 +561,7 @@ class ArchiveLineagePropagationTests(unittest.TestCase):
|
||||
self.assertEqual(child.metadata_json.get(worker_tasks_module.ARCHIVE_ROOT_ID_METADATA_KEY), str(parent_id))
|
||||
self.assertEqual(child.metadata_json.get(worker_tasks_module.ARCHIVE_DEPTH_METADATA_KEY), 1)
|
||||
self.assertTrue(child.is_archive_member)
|
||||
self.assertEqual(child.owner_user_id, parent.owner_user_id)
|
||||
|
||||
def test_resolve_archive_lineage_prefers_existing_metadata(self) -> None:
|
||||
"""Existing archive lineage metadata is reused without traversing parent relationships."""
|
||||
|
||||
Reference in New Issue
Block a user