chore: initialize from backend template 0a6dd0e
This commit is contained in:
@@ -0,0 +1,72 @@
|
||||
# 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.
|
||||
Reference in New Issue
Block a user