feat(antienum): 403 when sub can read, 404 otherwise

this is a UX improvement, always return a 404 not found when subject do not have any access on the resource
    but returns an explicit 403 forbidden is subject try a forbidden action on a resourse it can read

    regarding performance, the role is already in cache for the second call with read perm
This commit is contained in:
Edouard Vanbelle
2026-07-16 21:34:31 +02:00
parent 5b996bb218
commit 7aea383588
9 changed files with 252 additions and 153 deletions
+16 -12
View File
@@ -367,34 +367,38 @@ HTTP 200
jsonpath "$.items[?(@.resource.id=='{{perm_folder_id}}')].resource_type" == "folder"
jsonpath "$.items[?(@.resource.id=='{{perm_folder_id}}')].permissions" contains "read"
# ── Mutations still denied (Viewer has no Update/Create/Delete) ─
# ── Mutations still denied (Viewer has no Update/Create/Delete).
# Henry has Read via nested-group cascade → graduated denial
# returns 403 (see [[project_authz_require_graduated_denial]]).
# Anti-enum 404 stays reserved for the earlier phase where the
# cascade hadn't given Henry any Read at all.
POST {{base_url}}/api/folders
Authorization: Bearer {{henry_token}}
Content-Type: application/json
{ "name": "henry-attack-2", "parent_id": "{{perm_folder_id}}" }
HTTP 404
HTTP 403
PUT {{base_url}}/api/folders/{{perm_folder_id}}/rename
Authorization: Bearer {{henry_token}}
Content-Type: application/json
{ "name": "henry-rename-as-viewer" }
HTTP 404
HTTP 403
PUT {{base_url}}/api/files/{{perm_file_id}}/rename
Authorization: Bearer {{henry_token}}
Content-Type: application/json
{ "name": "henry-file-rename-as-viewer" }
HTTP 404
HTTP 403
PUT {{base_url}}/api/files/{{perm_file_id}}/thumbnail/icon
Authorization: Bearer {{henry_token}}
Content-Type: image/png
file,fixtures/blue-image.png;
HTTP 404
HTTP 403
POST {{base_url}}/api/files/upload
Authorization: Bearer {{henry_token}}
@@ -402,17 +406,17 @@ Authorization: Bearer {{henry_token}}
folder_id: {{perm_folder_id}}
file: file,fixtures/hello.txt; text/plain
HTTP 404
HTTP 403
DELETE {{base_url}}/api/files/{{perm_file_id}}
Authorization: Bearer {{henry_token}}
HTTP 404
HTTP 403
DELETE {{base_url}}/api/folders/{{perm_folder_id}}
Authorization: Bearer {{henry_token}}
HTTP 404
HTTP 403
# Viewer cannot start a chunked upload (no Create grant).
POST {{base_url}}/api/uploads
@@ -426,7 +430,7 @@ Content-Type: application/json
"chunk_size": 3000000
}
HTTP 404
HTTP 403
# ════════════════════════════════════════════════════════════════════
@@ -520,16 +524,16 @@ HTTP 200
[Asserts]
jsonpath "$[?(@.id=='{{henry_chunked_file_id}}')].name" == "henry-chunked-video.mp4"
# Editor still cannot delete.
# Editor still cannot delete. Editor bundle carries Read → 403.
DELETE {{base_url}}/api/files/{{perm_file_id}}
Authorization: Bearer {{henry_token}}
HTTP 404
HTTP 403
DELETE {{base_url}}/api/folders/{{perm_folder_id}}
Authorization: Bearer {{henry_token}}
HTTP 404
HTTP 403
# ════════════════════════════════════════════════════════════════════