feat(05-11): add UserDeleteConfirm model + admin password verification in delete_user
- Import verify_password from services.auth - Add UserDeleteConfirm Pydantic model (admin_password field) - delete_user handler now requires body; fails fast with 403 on wrong password - All existing SEC-09 cloud/MinIO purge logic and audit log unchanged - Three new tests pass: 204 on correct pw, 403 on wrong pw, 422 on no body
This commit is contained in:
+17
-1
@@ -37,7 +37,7 @@ from db.models import CloudConnection, Document, Quota, RefreshToken, Topic, Use
|
||||
from deps.auth import get_current_admin
|
||||
from deps.db import get_db
|
||||
from services.audit import write_audit_log
|
||||
from services.auth import hash_password, revoke_all_refresh_tokens
|
||||
from services.auth import hash_password, revoke_all_refresh_tokens, verify_password
|
||||
from storage import get_storage_backend, get_storage_backend_for_document
|
||||
|
||||
router = APIRouter(prefix="/api/admin", tags=["admin"])
|
||||
@@ -138,6 +138,12 @@ class SystemTopicCreate(BaseModel):
|
||||
color: str = "#6366f1"
|
||||
|
||||
|
||||
class UserDeleteConfirm(BaseModel):
|
||||
"""Admin password confirmation required before hard-deleting a user (ADMIN-02, T-05-11-01)."""
|
||||
|
||||
admin_password: str
|
||||
|
||||
|
||||
# ── SEC-08: Safe CloudConnection response model ───────────────────────────────
|
||||
|
||||
class CloudConnectionOut(BaseModel):
|
||||
@@ -472,6 +478,7 @@ async def update_ai_config(
|
||||
@router.delete("/users/{user_id}", status_code=status.HTTP_204_NO_CONTENT)
|
||||
async def delete_user(
|
||||
user_id: uuid.UUID,
|
||||
body: UserDeleteConfirm,
|
||||
request: Request,
|
||||
session: AsyncSession = Depends(get_db),
|
||||
_admin: User = Depends(get_current_admin),
|
||||
@@ -479,11 +486,20 @@ async def delete_user(
|
||||
"""Delete a user account and clean up all their MinIO objects (SEC-09, D-19).
|
||||
|
||||
Security invariants:
|
||||
- Admin password verified via Argon2 before any deletion (T-05-11-01)
|
||||
- Cannot delete admin accounts (T-04-07-04)
|
||||
- MinIO objects are deleted BEFORE DB records are removed (SEC-09)
|
||||
- MinIO deletion is best-effort (try/except) — DB row is deleted regardless
|
||||
- Audit log written with event_type="admin.user_deleted"
|
||||
"""
|
||||
# T-05-11-01: Verify admin password before performing any destructive action.
|
||||
# Fail fast — no DB reads for the target user until the admin is confirmed.
|
||||
if not verify_password(body.admin_password, _admin.password_hash):
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_403_FORBIDDEN,
|
||||
detail="Invalid admin password",
|
||||
)
|
||||
|
||||
user = await session.get(User, user_id)
|
||||
if user is None:
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="User not found")
|
||||
|
||||
Reference in New Issue
Block a user