Skip to content

test(e2e): negative-path Keycloak coverage#25

Merged
babs merged 1 commit into
masterfrom
feat/keycloak-e2e-negative-paths
Apr 27, 2026
Merged

test(e2e): negative-path Keycloak coverage#25
babs merged 1 commit into
masterfrom
feat/keycloak-e2e-negative-paths

Conversation

@babs
Copy link
Copy Markdown
Owner

@babs babs commented Apr 27, 2026

Summary

Closes T2.4 from `misc/next-steps.md`. Adds four negative-path tests against the real Keycloak demo stack so a regression in any security-critical denial path fails CI rather than production.

Test What it pins Spec
`TestKeycloakE2E_ConsentDenied` POST `/consent action=deny` → 302 to registered `redirect_uri` with `error=access_denied`, IdP login never reached RFC 6749 §4.1.2.1
`TestKeycloakE2E_ReplayedCode` Authorization code single-use: second `/token` exchange of same code → 400 `invalid_grant` + `error_code=code_replay` RFC 6749 §4.1.2
`TestKeycloakE2E_RefreshReuseRevokesFamily` Original refresh replayed past `REFRESH_RACE_GRACE_SEC` → `refresh_reuse_detected`; rotated sibling then → `refresh_family_revoked` (cascade pinned in one test) RFC 6749 §10.4 / OAuth 2.1 §6.1
`TestKeycloakE2E_ResourceMismatch` `/token` with `resource` that doesn't identify this AS → 400 `invalid_target` RFC 8707 §2.2

CI workflow change

`-run` pattern changed from a hardcoded single-test name to `^TestKeycloakE2E` (with `-v`). Future negative tests don't need workflow changes — explicit comment in the workflow names the convention.

Helpers extracted

  • `newE2EClient` — cookie-jar HTTP client with `CheckRedirect: ErrUseLastResponse`.
  • `refreshExchange` — happy-path rotation.
  • `postRefresh` — raw `POST /token` for refresh-grant tests that need to inspect failure shapes.
  • `extractConsentToken` — pulls the sealed token out of the consent HTML.

Threat-model

Rows 2 (active-IdP-session phishing), 4 (authorization-code replay), and 5 (refresh-token replay) now reference the corresponding e2e test names. The matrix stays the live audit artifact.

Verification

Verified locally against the running demo stack: all five `TestKeycloakE2E_*` tests pass in ~3.2s total. The 3s sleep in the refresh-reuse test dominates; the other four are sub-second.

Test plan

  • CI green (`test`, `lint`, `keycloak-e2e` (now running 5 tests), `fuzz-smoke`, `manifest-prod`, `govulncheck`, `build`).
  • Manual: run `go test -tags=keycloak_e2e -run "^TestKeycloakE2E" -count=1 -v .` against the demo stack and confirm all five pass.

Closes T2.4 from misc/next-steps.md. Adds four negative-path
tests against the real Keycloak demo stack so a regression in
any security-critical denial path fails CI rather than
production:

  - TestKeycloakE2E_ConsentDenied — POST /consent action=deny
    redirects 302 to the registered redirect_uri with
    error=access_denied per RFC 6749 §4.1.2.1; IdP login is
    never reached.

  - TestKeycloakE2E_ReplayedCode — a successful /token exchange
    consumes the authorization code; a second exchange with the
    same code is rejected as code_replay (RFC 6749 §4.1.2 MUST).

  - TestKeycloakE2E_RefreshReuseRevokesFamily — original refresh
    replayed past REFRESH_RACE_GRACE_SEC rejects as
    refresh_reuse_detected; the rotated sibling subsequently
    rejects as refresh_family_revoked. Pins both rejection paths
    of the cascade in one test.

  - TestKeycloakE2E_ResourceMismatch — /token with `resource`
    that does not identify this AS rejects as invalid_target
    per RFC 8707 §2.2.

CI workflow updated: -run pattern changed from a single
hardcoded test name to ^TestKeycloakE2E so future negative tests
land in the matrix without a workflow change.

Helpers extracted (newE2EClient, refreshExchange, postRefresh,
extractConsentToken) so adding more negative cases is a
copy-paste-and-tweak.

Threat-model rows 2/4/5 updated to reference the new tests.

Verified locally against the running demo stack: all five
TestKeycloakE2E_* tests pass in ~3.2s total (the 3s sleep in
the refresh-reuse test dominates).
@babs babs merged commit 7703839 into master Apr 27, 2026
7 checks passed
@babs babs deleted the feat/keycloak-e2e-negative-paths branch April 27, 2026 23:01
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.

1 participant