Add validation to prevent privilege escalation via is_superuser field and enhance related tests

- Added explicit Pydantic validation to reject modifications to `is_superuser` in `UserUpdate` schema.
- Updated backend logic in `users.py` to support defense-in-depth against privilege escalation.
- Introduced comprehensive tests for `/users` and `/users/me` endpoints to ensure `is_superuser` validation works correctly.
- Enhanced error handling and validation messages for better clarity and robustness.
This commit is contained in:
Felipe Cardoso
2025-11-01 16:15:03 +01:00
parent a82e5ea0e6
commit d75a8de91b
4 changed files with 58 additions and 15 deletions

View File

@@ -112,6 +112,26 @@ class TestUpdateCurrentUser:
json={"first_name": "Updated"}
)
@pytest.mark.asyncio
async def test_update_current_user_cannot_make_superuser(self, client, user_token):
"""Test that users cannot make themselves superuser (Pydantic validation)."""
response = await client.patch(
"/api/v1/users/me",
headers={"Authorization": f"Bearer {user_token}"},
json={"is_superuser": True}
)
# Pydantic validation should reject this at the schema level
assert response.status_code == status.HTTP_422_UNPROCESSABLE_ENTITY
data = response.json()
assert data["success"] is False
assert "errors" in data
# Check that the error mentions is_superuser
error_fields = [err["field"] for err in data["errors"]]
assert "is_superuser" in error_fields
error_messages = [err["message"] for err in data["errors"]]
assert any("superuser" in msg.lower() for msg in error_messages)
@pytest.mark.asyncio
async def test_update_current_user_value_error(self, client, user_token):
"""Test ValueError handling during update (covers lines 165-166)."""
@@ -168,6 +188,18 @@ class TestUpdateUserById:
assert response.status_code == status.HTTP_404_NOT_FOUND
@pytest.mark.asyncio
async def test_update_user_by_id_non_superuser_cannot_change_superuser_status(self, client, async_test_user, user_token):
"""Test non-superuser cannot modify superuser status (Pydantic validation)."""
response = await client.patch(
f"/api/v1/users/{async_test_user.id}",
headers={"Authorization": f"Bearer {user_token}"},
json={"is_superuser": True}
)
# Pydantic validation should reject this at the schema level
assert response.status_code == status.HTTP_422_UNPROCESSABLE_ENTITY
@pytest.mark.asyncio
async def test_update_user_by_id_success(self, client, async_test_user, superuser_token):
"""Test updating user successfully (covers lines 276-278)."""