| """ |
| Admin Authorization Security Tests |
| |
| Tests cover: |
| - Super admin role requirement for administrative endpoints |
| - Standard user access denial to admin endpoints |
| - WebSocket management authorization |
| - Rating sync authorization |
| - Conflict management authorization |
| """ |
| import pytest |
| from fastapi.testclient import TestClient |
| from sqlalchemy.orm import Session |
|
|
| from tests.factories.user_factory import UserFactory |
| from tests.security.conftest import create_test_token |
|
|
|
|
| class TestWebSocketManagementAuthorization: |
| """Test WebSocket management endpoint authorization.""" |
|
|
| def test_websocket_status_requires_super_admin(self, client: TestClient, db_session: Session): |
| """Test that websocket status endpoint requires super_admin role.""" |
| |
| standard_user = UserFactory( |
| email="standard@test.com", |
| role="member", |
| _session=db_session |
| ) |
|
|
| |
| response = client.get( |
| "/api/admin/websocket/status", |
| headers={"Authorization": f"Bearer {create_test_token(standard_user.id)}"} |
| ) |
|
|
| |
| assert response.status_code == 403 |
| |
| error_detail = response.json() |
| if isinstance(error_detail, dict): |
| detail = error_detail.get("detail", "") |
| assert "super_admin" in str(detail).lower() or "permission" in str(detail).lower() |
|
|
| def test_websocket_disable_requires_super_admin(self, client: TestClient, db_session: Session): |
| """Test that websocket disable endpoint requires super_admin role.""" |
| standard_user = UserFactory( |
| email="standard@test.com", |
| role="member", |
| _session=db_session |
| ) |
|
|
| response = client.post( |
| "/api/admin/websocket/disable", |
| headers={"Authorization": f"Bearer {create_test_token(standard_user.id)}"} |
| ) |
|
|
| |
| assert response.status_code == 403 |
|
|
| def test_websocket_enable_requires_super_admin(self, client: TestClient, db_session: Session): |
| """Test that websocket enable endpoint requires super_admin role.""" |
| standard_user = UserFactory( |
| email="standard@test.com", |
| role="member", |
| _session=db_session |
| ) |
|
|
| response = client.post( |
| "/api/admin/websocket/enable", |
| headers={"Authorization": f"Bearer {create_test_token(standard_user.id)}"} |
| ) |
|
|
| |
| assert response.status_code == 403 |
|
|
| def test_websocket_reconnect_requires_super_admin(self, client: TestClient, db_session: Session): |
| """Test that websocket reconnect endpoint requires super_admin role.""" |
| standard_user = UserFactory( |
| email="standard@test.com", |
| role="member", |
| _session=db_session |
| ) |
|
|
| response = client.post( |
| "/api/admin/websocket/reconnect", |
| headers={"Authorization": f"Bearer {create_test_token(standard_user.id)}"} |
| ) |
|
|
| |
| assert response.status_code == 403 |
|
|
|
|
| class TestRatingSyncAuthorization: |
| """Test rating sync endpoint authorization.""" |
|
|
| def test_trigger_rating_sync_requires_super_admin(self, client: TestClient, db_session: Session): |
| """Test that rating sync endpoint requires super_admin role.""" |
| standard_user = UserFactory( |
| email="standard@test.com", |
| role="member", |
| _session=db_session |
| ) |
|
|
| response = client.post( |
| "/api/admin/sync/ratings", |
| json={"upload_all": False}, |
| headers={"Authorization": f"Bearer {create_test_token(standard_user.id)}"} |
| ) |
|
|
| |
| assert response.status_code == 403 |
|
|
| def test_get_failed_rating_uploads_requires_super_admin(self, client: TestClient, db_session: Session): |
| """Test that failed uploads endpoint requires super_admin role.""" |
| standard_user = UserFactory( |
| email="standard@test.com", |
| role="member", |
| _session=db_session |
| ) |
|
|
| response = client.get( |
| "/api/admin/ratings/failed-uploads", |
| headers={"Authorization": f"Bearer {create_test_token(standard_user.id)}"} |
| ) |
|
|
| |
| assert response.status_code == 403 |
|
|
| def test_retry_failed_rating_upload_requires_super_admin(self, client: TestClient, db_session: Session): |
| """Test that retry upload endpoint requires super_admin role.""" |
| standard_user = UserFactory( |
| email="standard@test.com", |
| role="member", |
| _session=db_session |
| ) |
|
|
| response = client.post( |
| "/api/admin/ratings/failed-uploads/test-id/retry", |
| headers={"Authorization": f"Bearer {create_test_token(standard_user.id)}"} |
| ) |
|
|
| |
| assert response.status_code == 403 |
|
|
|
|
| class TestConflictManagementAuthorization: |
| """Test conflict management endpoint authorization.""" |
|
|
| def test_list_conflicts_requires_super_admin(self, client: TestClient, db_session: Session): |
| """Test that list conflicts endpoint requires super_admin role.""" |
| standard_user = UserFactory( |
| email="standard@test.com", |
| role="member", |
| _session=db_session |
| ) |
|
|
| response = client.get( |
| "/api/admin/conflicts", |
| headers={"Authorization": f"Bearer {create_test_token(standard_user.id)}"} |
| ) |
|
|
| |
| assert response.status_code == 403 |
|
|
| def test_get_conflict_requires_super_admin(self, client: TestClient, db_session: Session): |
| """Test that get conflict endpoint requires super_admin role.""" |
| standard_user = UserFactory( |
| email="standard@test.com", |
| role="member", |
| _session=db_session |
| ) |
|
|
| response = client.get( |
| "/api/admin/conflicts/1", |
| headers={"Authorization": f"Bearer {create_test_token(standard_user.id)}"} |
| ) |
|
|
| |
| assert response.status_code == 403 |
|
|
| def test_resolve_conflict_requires_super_admin(self, client: TestClient, db_session: Session): |
| """Test that resolve conflict endpoint requires super_admin role.""" |
| standard_user = UserFactory( |
| email="standard@test.com", |
| role="member", |
| _session=db_session |
| ) |
|
|
| response = client.post( |
| "/api/admin/conflicts/1/resolve", |
| json={ |
| "strategy": "remote_wins", |
| "resolved_by": "admin@example.com" |
| }, |
| headers={"Authorization": f"Bearer {create_test_token(standard_user.id)}"} |
| ) |
|
|
| |
| assert response.status_code == 403 |
|
|
| def test_bulk_resolve_conflicts_requires_super_admin(self, client: TestClient, db_session: Session): |
| """Test that bulk resolve conflicts endpoint requires super_admin role.""" |
| standard_user = UserFactory( |
| email="standard@test.com", |
| role="member", |
| _session=db_session |
| ) |
|
|
| response = client.post( |
| "/api/admin/conflicts/bulk-resolve", |
| json={ |
| "conflict_ids": [1, 2, 3], |
| "strategy": "remote_wins", |
| "resolved_by": "admin@example.com" |
| }, |
| headers={"Authorization": f"Bearer {create_test_token(standard_user.id)}"} |
| ) |
|
|
| |
| assert response.status_code == 403 |
|
|
|
|
| class TestAdminAuthorizationBypassAttempts: |
| """Test that various user roles cannot bypass admin authorization.""" |
|
|
| @pytest.mark.parametrize("role", ["member", "admin", "viewer", "editor"]) |
| def test_non_super_admin_roles_denied_websocket_access(self, client: TestClient, db_session: Session, role: str): |
| """Test that all non-super_admin roles are denied access to websocket endpoints.""" |
| |
| user = UserFactory( |
| email=f"{role}@test.com", |
| role=role, |
| _session=db_session |
| ) |
|
|
| response = client.get( |
| "/api/admin/websocket/status", |
| headers={"Authorization": f"Bearer {create_test_token(user.id)}"} |
| ) |
|
|
| |
| assert response.status_code == 403 |
|
|
| @pytest.mark.parametrize("role", ["member", "admin", "viewer", "editor"]) |
| def test_non_super_admin_roles_denied_conflict_access(self, client: TestClient, db_session: Session, role: str): |
| """Test that all non-super_admin roles are denied access to conflict endpoints.""" |
| user = UserFactory( |
| email=f"{role}@test.com", |
| role=role, |
| _session=db_session |
| ) |
|
|
| response = client.get( |
| "/api/admin/conflicts", |
| headers={"Authorization": f"Bearer {create_test_token(user.id)}"} |
| ) |
|
|
| |
| assert response.status_code == 403 |
|
|
|
|
| class TestUnauthenticatedAccess: |
| """Test that unauthenticated requests are denied.""" |
|
|
| def test_websocket_status_requires_authentication(self, client: TestClient): |
| """Test that websocket status endpoint requires authentication.""" |
| response = client.get("/api/admin/websocket/status") |
| assert response.status_code in [401, 403] |
|
|
| def test_conflict_list_requires_authentication(self, client: TestClient): |
| """Test that conflict list endpoint requires authentication.""" |
| response = client.get("/api/admin/conflicts") |
| assert response.status_code in [401, 403] |
|
|
| def test_rating_sync_requires_authentication(self, client: TestClient): |
| """Test that rating sync endpoint requires authentication.""" |
| response = client.post("/api/admin/sync/ratings", json={}) |
| assert response.status_code in [401, 403] |
|
|