Add missing @PreAuthorize to ProcessRestRepository#delete - #1386
Add missing @PreAuthorize to ProcessRestRepository#delete#1386MatusBeke wants to merge 2 commits into
Conversation
DELETE /api/system/processes/{id} had no method-level authorization
check, unlike its siblings (findOne, findAll, findByCurrentUser). The
only check lived inside ProcessServiceImpl#delete's per-bitstream
loop, so a process with zero bitstreams (e.g. status SCHEDULED)
skipped the loop entirely and bypassed authorization, letting an
anonymous DELETE remove any process record.
Adds hasPermission(#integer, 'PROCESS', 'DELETE'), matching findOne.
Reuses the existing ProcessRestPermissionEvaluatorPlugin (owner-or-
admin check, independent of READ/WRITE/DELETE) - no new plugin needed.
Originated from security audit (2026_07_20_dq)
There was a problem hiding this comment.
Pull request overview
Tightens security on the System Processes REST API by adding a missing method-level authorization check to prevent unauthorized deletion of process records via DELETE /api/system/processes/{id}.
Changes:
- Adds
@PreAuthorize("hasPermission(#…, 'PROCESS', 'DELETE')")toProcessRestRepository#deleteto align with existing authorization patterns on related endpoints.
| @PreAuthorize("hasPermission(#integer, 'PROCESS', 'DELETE')") | ||
| protected void delete(Context context, Integer integer) | ||
| throws AuthorizeException, RepositoryMethodNotImplementedException { |
There was a problem hiding this comment.
Fixed: renamed the parameter from integer to id (and updated the SpEL expression to #id), matching the convention used elsewhere in this class. Files: ProcessRestRepository.java. Validation: mvn -pl dspace-server-webapp -am install (BUILD SUCCESS) + checkstyle:check (0 violations).
| } | ||
|
|
||
| @Override | ||
| @PreAuthorize("hasPermission(#integer, 'PROCESS', 'DELETE')") |
There was a problem hiding this comment.
Fixed: added 3 cases to ProcessRestRepositoryIT covering DELETE authorization on the exact bitstream-less/SCHEDULED process shape that bypassed the check: deleteProcessAdmin (204, then 404 on re-fetch), deleteProcessAnonymousUnauthorizedException (401), deleteProcessForDifferentUserForbiddenException (403). Files: ProcessRestRepositoryIT.java. Validation: compiles clean under failsafe locally; full run needs the Docker Postgres/Solr stack this repo's CI already provisions (skipIntegrationTests=false in build.yml), so the authoritative run is the CI check on this PR.
- Rename delete()'s parameter from `integer` to `id` for consistency with the rest of the repository and to make the SpEL expression read clearly (#id vs #integer). - Add ProcessRestRepositoryIT coverage for DELETE authorization on the bitstream-less/SCHEDULED process shape that previously bypassed the check entirely: admin succeeds (204, then 404 on re-fetch), anonymous is rejected (401), and a different authenticated user is rejected (403). Addresses both Copilot review comments on PR #1386.
Problem
DELETE /api/system/processes/{id}had no method-level authorization check. An anonymous, unauthenticated request could delete any process record.Root cause
ProcessRestRepository#deletelacked@PreAuthorize, unlike its siblings (findOne,findAll,findByCurrentUser). The only authorization check lived insideProcessServiceImpl#delete's per-bitstream loop (viabitstreamService.delete()). A process with zero bitstreams (e.g. statusSCHEDULED) skips that loop entirely, so the check never runs and the delete proceeds unauthorized.Change set
Adds
@PreAuthorize("hasPermission(#integer, 'PROCESS', 'DELETE')")onProcessRestRepository#delete, mirroring the existing pattern already used onfindOne. Reuses the existingProcessRestPermissionEvaluatorPlugin(owner-or-admin check, independent of READ/WRITE/DELETE) — no new plugin needed. One line, no other changes; out of scope: adding a regression IT for the zero-bitstream case (flagged below as a follow-up).Test evidence
Risk & rollback
Purely additive authorization check — only tightens access; the existing owner/admin callers are unaffected. Rollback = revert the single annotation line.
Notes / assumptions
ProcessRestRepositoryITcase asserting an anonymousDELETEon a bitstream-less (SCHEDULED) process now returns 401/403 instead of 204.