122 lines
6.6 KiB
Markdown
122 lines
6.6 KiB
Markdown
---
|
|
phase: 08-oauth2-1-authorization-server
|
|
plan: 04
|
|
type: execute
|
|
wave: 4
|
|
depends_on: [08-03]
|
|
files_modified:
|
|
- wristband/authorize.go
|
|
- wristband/token.go
|
|
- wristband/authorize_test.go
|
|
- wristband/token_test.go
|
|
- ../fonoteka.go/plugins/golem15/fonoteka/classes/auth/oauth_store.go
|
|
- ../fonoteka.go/plugins/golem15/fonoteka/classes/auth/oauth_token_issuer.go
|
|
- ../fonoteka.go/plugins/golem15/fonoteka/classes/auth/api_token_manager.go
|
|
autonomous: true
|
|
requirements: [AUTH-05, AUTH-06]
|
|
must_haves:
|
|
truths:
|
|
- "D-02: Authorize reads query only and token rejects JSON before ParseForm body-over-query parsing."
|
|
- "D-04: S256/client-secret comparisons are constant-time and code replay has one winner."
|
|
- "D-05: Wristband owns authorize, PKCE, scope/resource policy, and atomic code exchange."
|
|
- "D-11: Issued access tokens retain the configured inv_ prefix."
|
|
artifacts:
|
|
- path: "wristband/authorize.go"
|
|
provides: "Ordered validation, redirects, PKCE, resource and scope policy"
|
|
- path: "wristband/token.go"
|
|
provides: "Client authentication and atomic authorization-code exchange"
|
|
key_links:
|
|
- from: "wristband/token.go"
|
|
to: "oauth_token_issuer.go"
|
|
via: "single transaction-bound Tx"
|
|
pattern: "WithinTx"
|
|
---
|
|
|
|
<objective>
|
|
Implement the protocol core from authorize validation through one atomic authorization-code exchange.
|
|
|
|
Purpose: Prove PKCE, redirect, parser, scope, client-auth, and code-replay rules independently of the browser controller.
|
|
Output: Authorize/token handlers, issuer adapter, store transitions, and deterministic/concurrent tests.
|
|
</objective>
|
|
|
|
<execution_context>
|
|
@/home/jin/.codex/get-shit-done/workflows/execute-plan.md
|
|
@/home/jin/.codex/get-shit-done/templates/summary.md
|
|
</execution_context>
|
|
|
|
<context>
|
|
@.planning/PROJECT.md
|
|
@.planning/ROADMAP.md
|
|
@.planning/STATE.md
|
|
@.planning/phases/08-oauth2-1-authorization-server/08-CONTEXT.md
|
|
@.planning/phases/08-oauth2-1-authorization-server/08-RESEARCH.md
|
|
@.planning/phases/08-oauth2-1-authorization-server/08-03-SUMMARY.md
|
|
</context>
|
|
|
|
<tasks>
|
|
|
|
<task type="auto" tdd="true">
|
|
<name>Task 1: Specify authorize and code exchange with executable RED tests</name>
|
|
<files>wristband/authorize.go, wristband/token.go, wristband/authorize_test.go, wristband/token_test.go, ../fonoteka.go/plugins/golem15/fonoteka/classes/auth/oauth_store.go, ../fonoteka.go/plugins/golem15/fonoteka/classes/auth/oauth_token_issuer.go</files>
|
|
<behavior>
|
|
- Unknown client/unregistered redirect are local 400 without Location; later errors use exact ordered RFC3986 redirects.
|
|
- S256 is mandatory; parser precedence, Basic override, cache headers, and exact challenge are tested.
|
|
- Tests compile and fail only through `PHASE8_RED:authorize-token`.
|
|
</behavior>
|
|
<action>D-18: extend the existing interfaces with compiling authorize/token stubs and add deterministic unit plus real-store adapter tests. Use explicit `PHASE8_RED:authorize-token` assertions for absent behavior. Reject syntax/build/setup/missing-test failures through the shared RED verifier. Cover T-08-PKCE, CODE-REPLAY, OPEN-REDIRECT, SECRET-TIMING, SCOPE-CEILING, and REQUEST-LEAK, including synchronized concurrent code exchange.</action>
|
|
<verify>
|
|
<automated>scripts/check-phase8-red.sh authorize-token go test ./wristband -run 'Test(Authorize|Token|PKCE|Code)' -count=1</automated>
|
|
</verify>
|
|
<done>Named tests compile and execute, with the verifier accepting only the intended missing-behavior marker.</done>
|
|
</task>
|
|
|
|
<task type="auto" tdd="true">
|
|
<name>Task 2: Implement ordered authorize and atomic code exchange</name>
|
|
<files>wristband/authorize.go, wristband/token.go, wristband/authorize_test.go, wristband/token_test.go, ../fonoteka.go/plugins/golem15/fonoteka/classes/auth/oauth_store.go, ../fonoteka.go/plugins/golem15/fonoteka/classes/auth/oauth_token_issuer.go, ../fonoteka.go/plugins/golem15/fonoteka/classes/auth/api_token_manager.go</files>
|
|
<behavior>
|
|
- Validation order is usable client, exact redirect, response type, S256 method/challenge, scope ceiling, resource, pending creation.
|
|
- Code lock/consume, access-token mint/stamp, and refresh creation commit atomically once.
|
|
</behavior>
|
|
<action>D-02: implement endpoint-specific parsing and reject JSON token calls before ParseForm. D-03: apply configured TTL/resource. D-04: compare fixed transforms with `subtle.ConstantTimeCompare`. D-05 and D-06: keep state/policy and exact raw responses in wristband. D-07: exchange under one app transaction/row lock. Build redirects from ordered pairs, never `url.Values.Encode`. D-11: make the app adapter prefix config-backed while retaining `inv_`. D-17: run expired-only sweep on token entry. Preserve exact `Basic realm="OAuth"`, no-store, and no-cache headers.</action>
|
|
<verify>
|
|
<automated>go test ./wristband -run 'Test(Authorize|Token|PKCE|Code)' -count=1 && cd ../fonoteka.go && go test ./plugins/golem15/fonoteka/classes/auth -run 'TestOAuth(Code|Issuer)' -count=1</automated>
|
|
</verify>
|
|
<done>One exact PKCE-bound code produces one inv_ access/refresh grant, and all validation/parser/replay failures are exact and tested.</done>
|
|
</task>
|
|
|
|
</tasks>
|
|
|
|
<threat_model>
|
|
## Trust Boundaries
|
|
|
|
| Boundary | Description |
|
|
|----------|-------------|
|
|
| Connector → authorize/token | Untrusted query/form/Basic input requests or redeems authority. |
|
|
| Tx → access-token store | One-time code state becomes durable credentials. |
|
|
|
|
## STRIDE Threat Register
|
|
|
|
| Threat ID | Category | Component | Disposition | Mitigation Plan |
|
|
|-----------|----------|-----------|-------------|-----------------|
|
|
| T-08-PKCE | Spoofing/Elevation | authorize/token | mitigate | Mandatory S256 syntax and constant-time comparison. |
|
|
| T-08-CODE-REPLAY | Spoofing | exchange | mitigate | Row lock, single transaction, concurrent one-winner test. |
|
|
| T-08-OPEN-REDIRECT | Spoofing/Disclosure | authorize | mitigate | Exact redirect validation before any redirect. |
|
|
| T-08-SECRET-TIMING | Information Disclosure | client auth | mitigate | Fixed transforms and constant-time compare. |
|
|
| T-08-SCOPE-CEILING | Elevation | authorize | mitigate | Requested ∩ client ceiling before persistence. |
|
|
| T-08-SC | Tampering | dependencies | mitigate | Standard library and existing app services only. |
|
|
</threat_model>
|
|
|
|
<verification>
|
|
- Focused wristband and issuer/store tests pass.
|
|
- `go test -race ./wristband` passes at wave boundary.
|
|
</verification>
|
|
|
|
<success_criteria>
|
|
- Authorize and token protocol behavior is exact, concurrency-safe, and app-agnostic.
|
|
- The configured personal-token issuer produces the unchanged inv_ wire format.
|
|
</success_criteria>
|
|
|
|
<output>
|
|
Create `.planning/phases/08-oauth2-1-authorization-server/08-04-SUMMARY.md` when done.
|
|
</output>
|