Skip to content

request-validation: 403 auth-deny for uniformly-secured APIs (Hub)#394

Draft
esraagamal6 wants to merge 1 commit into
mainfrom
feat/hub-auth-deny-403
Draft

request-validation: 403 auth-deny for uniformly-secured APIs (Hub)#394
esraagamal6 wants to merge 1 commit into
mainfrom
feat/hub-auth-deny-403

Conversation

@esraagamal6

Copy link
Copy Markdown
Contributor

What

Phase B of the Camunda Hub negative-suite auth coverage (camunda-hub#25264) — 403 unauthorized. Phase A (401) landed in #391; this closes #392.

Adds an all-secured mode to the 403 auth-deny generator for APIs that authorize every op via a single scheme and short-circuit the authority check before any resource lookup — Camunda Hub's @PreAuthorize("hasAuthority(...) && hasAccessToOrganization(...)"). A reduced-permission Bearer probe is therefore denied 403 on every secured op with dummy keys (no fixtures).

This is the zero-permission probe approach (option 1): full surface coverage, generic "this op is permission-gated" assertion — the same model OCA's auth-deny uses, but extended from a 7-op read slice to the whole secured surface (Hub's short-circuit removes OCA's need for real fixtures).

Changes

  • Config — new per-config authDenyMode: 'slice' | 'all-secured' (default 'slice', preserving OCA's read-side allowlist). Mirrors request-validation: 401 negatives for uniformly-secured APIs (Hub) — missing + invalid token #391's authAbsentMode.
  • GeneratorgenerateAuthDeny all-secured branch: one 403 scenario per secured op (reusing the secured field the 401 generators target, so the 403 surface matches the 401 surface), dummy path keys, no body. No SLICE, no fixtures.
  • Bearer probedenyProbeHeaders() returns a Bearer token when RBAC_DENY_PROBE_BEARER_TOKEN is set (Hub), else the Basic zero-grant probe user (OCA). The rbac global-setup skips fixture/probe-user provisioning in Bearer-probe mode.
  • Keycloak/docker — a reduced-permission c8-client-deny M2M client (no public-api authorities); start-hub.sh adds it a web-modeler-api audience mapper so its token authenticates (passes 401) and reaches the 403 gate.
  • Hub config opts in; README documents minting the probe token + RV_PROFILE=rbac. OCA auth-deny unchanged.
  • Tests — all-secured generator (targeting, dummy keys, filter, slice-isolation) + denyProbeHeaders Bearer/Basic switch.

Generation

CONFIG=camunda-hub npm run generate:request-validation emits 29 rbac deny-tests (one per secured op, matching the 401 surface).

Open / remaining (why this is a draft)

  • Live validation against a secured local Hub (acceptance criterion). Confirms every op returns 403, not 401/404.
  • Body-ordering check for write ops. Hub authorizes via method-level @PreAuthorize, which runs after @RequestBody deserialization/validation. A bodyless POST create could return 400 before the 403. If the live run shows that, this PR will exclude required-body ops (bodyRequired === true) from the all-secured surface with a documented note, deferring create/update deny-tests (which need a valid body) to a follow-up.
  • Per-permission deny/allow precision (which exact CRUD authority is enforced) remains a follow-up, as it does for OCA.

🤖 Generated with Claude Code

Phase B of the Hub negative-suite auth coverage (camunda/camunda-hub#25264);
401 (Phase A) landed in #391. Adds an `all-secured` mode to the 403 auth-deny
generator for APIs that authorize every op via a single scheme and short-circuit
the authority check before any resource lookup (Camunda Hub:
`hasAuthority(...) && hasAccessToOrganization(...)`).

- New per-config `authDenyMode: 'slice' | 'all-secured'` (default 'slice',
  preserving OCA's read-side allowlist). Hub uses 'all-secured'.
- `generateAuthDeny` all-secured branch: one 403 scenario per `secured` op
  (reusing the `secured` field the 401 generators target, so the 403 surface
  matches the 401 surface) with dummy path keys and no request body. No SLICE,
  no fixtures — the dummy key is never dereferenced because authority is denied
  first.
- Bearer deny probe: `denyProbeHeaders()` returns a Bearer token when
  `RBAC_DENY_PROBE_BEARER_TOKEN` is set (Hub), else the Basic zero-grant probe
  user (OCA). The rbac global-setup skips all fixture/probe-user provisioning in
  Bearer-probe mode.
- Keycloak: a reduced-permission `c8-client-deny` M2M client (no public-api
  authorities). start-hub.sh adds it a web-modeler-api audience mapper so its
  token authenticates (passes 401) and reaches the authorization (403) gate.
- Hub config opts in (`authDenyMode: 'all-secured'`); README documents minting
  the probe token and running RV_PROFILE=rbac. OCA auth-deny unchanged.
- Unit tests for the all-secured generator (targeting, dummy keys, filter) and
  the denyProbeHeaders Bearer/Basic switch.

Generates 29 rbac deny-tests for Hub (one per secured op). Live validation
against a secured local Hub is the remaining acceptance step.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

request-validation: 403 auth-deny for Hub (missing-permission probe token)

1 participant