73 lines
3.8 KiB
Markdown
73 lines
3.8 KiB
Markdown
# Web Security Boundary Design
|
|
|
|
**Date:** 2026-08-02
|
|
**Status:** approved by the user's instruction to apply the reviewed P1/P2 work sequentially
|
|
**Scope:** JWT/OIDC/JWKS and CORS behavior at the `adapter:inbound:web` Spring Security filter boundary
|
|
|
|
## Context
|
|
|
|
The module has unit contracts for JWT validators, exception classification, envelope writers, and
|
|
CORS settings. It does not yet prove that a real bearer request crosses issuer discovery, JWKS
|
|
retrieval, signature/claim validation, principal conversion, `SecurityFilterChain`, and the public
|
|
error envelope. CORS configuration is likewise untested at the filter boundary, where preflight
|
|
ordering relative to authentication is the important behavior.
|
|
|
|
These are release-boundary checks and must not silently skip because an external IdP, environment
|
|
variable, or optional flag is absent.
|
|
|
|
## Decision
|
|
|
|
Add a dedicated `webSecurityBoundaryTest` task that reuses the ordinary test output/classpath and
|
|
runs only JUnit tests tagged `security-boundary`. Ordinary `test` excludes that tag so each contract
|
|
runs once. The dedicated task:
|
|
|
|
- fails when no tests are discovered;
|
|
- disables up-to-date reuse;
|
|
- fails the root suite when any test reports `SKIPPED`;
|
|
- is required by the inbound-web `check` task;
|
|
- uses UTC and no environment-dependent conditions or assumptions.
|
|
|
|
JWT tests use a JDK loopback `HttpServer` bound to `127.0.0.1` on an ephemeral port. It serves the
|
|
minimum OIDC discovery document and JWKS response. Tests generate ephemeral RSA keys and compact
|
|
RS256 JWTs with the already-resolved Nimbus dependency; no new library or external network is
|
|
allowed. Each failure case uses a fresh server and Spring context to prevent decoder/JWK cache
|
|
cross-contamination.
|
|
|
|
CORS tests build the production `SecurityConfig` and real `springSecurityFilterChain` with direct
|
|
configuration properties. They issue real preflight and actual-origin MockMvc requests. A test JWT
|
|
decoder bean is allowed here because CORS ordering—not token decoding—is the owned boundary.
|
|
|
|
## JWT/JWKS Contract
|
|
|
|
- application context startup performs zero discovery/JWKS calls (lazy decoder);
|
|
- a correctly signed token reaches a protected controller and exposes the expected
|
|
`AuthenticatedPrincipal` subject/roles;
|
|
- expiry beyond the configured 60-second skew, issuer mismatch, audience mismatch, wrong
|
|
signature, and unknown `kid` produce their exact stable 401 error codes and bounded
|
|
`WWW-Authenticate`/`Retry-After` headers;
|
|
- deterministic JWKS 503 produces `AUTH_JWKS_UNAVAILABLE`, HTTP 503, and `Retry-After: 30`;
|
|
- after that first-request 503, the same lazy decoder/context retries initialization and succeeds
|
|
once the JWKS endpoint recovers;
|
|
- discovery metadata that is fetched successfully but is internally inconsistent produces the
|
|
fixed 500 `INTERNAL_AUTH_MISCONFIGURATION` envelope rather than a raw initialization exception;
|
|
- responses never contain the bearer token, issuer URL, `kid`, JWK material, or internal decoder
|
|
diagnostics.
|
|
|
|
## CORS Contract
|
|
|
|
- an approved credentialed preflight to an authenticated endpoint succeeds before bearer
|
|
authentication and emits exact origin/credentials/method/header/max-age policy;
|
|
- an unapproved origin receives 403 without allow-origin or allow-credentials reflection;
|
|
- disabled CORS emits no CORS response headers;
|
|
- wildcard origin without credentials returns `*` and no credentials header;
|
|
- an approved actual-origin request receives matching CORS and bounded `Vary` headers;
|
|
- wildcard plus credentials remains a settings startup failure (already covered by settings tests).
|
|
|
|
## Non-Goals
|
|
|
|
- external IdP/TLS/rotation rehearsal;
|
|
- browser-engine SameSite behavior;
|
|
- Redis-backed session continuity (the next P1 batch);
|
|
- new test libraries, Docker, or changes to production dependency direction;
|
|
- staging, commit, amend, or push by an agent.
|