docs(04-02): complete security filter chain wiring plan
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -43,8 +43,8 @@ Requirements for initial release. Each maps to roadmap phases. Tracked as Gitea
|
|||||||
|
|
||||||
### Security
|
### Security
|
||||||
|
|
||||||
- [ ] **SECU-01**: All API endpoints (except health and register) require valid JWT Bearer token (#23)
|
- [x] **SECU-01**: All API endpoints (except health and register) require valid JWT Bearer token (#23)
|
||||||
- [ ] **SECU-02**: JWT refresh flow via `POST /api/v1/agents/{id}/refresh` (#24)
|
- [x] **SECU-02**: JWT refresh flow via `POST /api/v1/agents/{id}/refresh` (#24)
|
||||||
- [x] **SECU-03**: Server generates Ed25519 keypair; public key delivered at registration (#25)
|
- [x] **SECU-03**: Server generates Ed25519 keypair; public key delivered at registration (#25)
|
||||||
- [x] **SECU-04**: All config-update and replay SSE payloads are signed with server's Ed25519 private key (#26)
|
- [x] **SECU-04**: All config-update and replay SSE payloads are signed with server's Ed25519 private key (#26)
|
||||||
- [x] **SECU-05**: Bootstrap token from `CAMELEER_AUTH_TOKEN` env var validates initial agent registration (#27)
|
- [x] **SECU-05**: Bootstrap token from `CAMELEER_AUTH_TOKEN` env var validates initial agent registration (#27)
|
||||||
|
|||||||
@@ -2,10 +2,10 @@
|
|||||||
gsd_state_version: 1.0
|
gsd_state_version: 1.0
|
||||||
milestone: v1.0
|
milestone: v1.0
|
||||||
milestone_name: milestone
|
milestone_name: milestone
|
||||||
status: in-progress
|
status: executing
|
||||||
stopped_at: Completed 04-03-PLAN.md
|
stopped_at: Completed 04-02-PLAN.md
|
||||||
last_updated: "2026-03-11T19:29:30Z"
|
last_updated: "2026-03-11T19:40:20.252Z"
|
||||||
last_activity: 2026-03-11 -- Completed 04-03 (SSE payload signing)
|
last_activity: 2026-03-11 -- Completed 04-02 (Security filter chain wiring)
|
||||||
progress:
|
progress:
|
||||||
total_phases: 4
|
total_phases: 4
|
||||||
completed_phases: 4
|
completed_phases: 4
|
||||||
@@ -26,9 +26,9 @@ See: .planning/PROJECT.md (updated 2026-03-11)
|
|||||||
## Current Position
|
## Current Position
|
||||||
|
|
||||||
Phase: 4 of 4 (Security)
|
Phase: 4 of 4 (Security)
|
||||||
Plan: 3 of 3 in current phase (SSE payload signing)
|
Plan: 2 of 3 in current phase (Security filter chain wiring)
|
||||||
Status: Phase 04 complete, all plans done
|
Status: Phase 04 in progress, Plan 02 complete
|
||||||
Last activity: 2026-03-11 -- Completed 04-03 (SSE payload signing)
|
Last activity: 2026-03-11 -- Completed 04-02 (Security filter chain wiring)
|
||||||
|
|
||||||
Progress: [██████████] 100%
|
Progress: [██████████] 100%
|
||||||
|
|
||||||
@@ -61,6 +61,7 @@ Progress: [██████████] 100%
|
|||||||
| Phase 03 P02 | 32min | 2 tasks | 7 files |
|
| Phase 03 P02 | 32min | 2 tasks | 7 files |
|
||||||
| Phase 04 P01 | 12min | 1 tasks | 15 files |
|
| Phase 04 P01 | 12min | 1 tasks | 15 files |
|
||||||
| Phase 04 P03 | 17min | 1 tasks | 4 files |
|
| Phase 04 P03 | 17min | 1 tasks | 4 files |
|
||||||
|
| Phase 04 P02 | 26min | 2 tasks | 25 files |
|
||||||
|
|
||||||
## Accumulated Context
|
## Accumulated Context
|
||||||
|
|
||||||
@@ -109,6 +110,9 @@ Recent decisions affecting current work:
|
|||||||
- [Phase 04]: InitializingBean pattern for fail-fast bootstrap token validation on startup
|
- [Phase 04]: InitializingBean pattern for fail-fast bootstrap token validation on startup
|
||||||
- [Phase 04]: Signed payload parsed to JsonNode for correct SseEmitter serialization (avoids double-quoting)
|
- [Phase 04]: Signed payload parsed to JsonNode for correct SseEmitter serialization (avoids double-quoting)
|
||||||
- [Phase 04]: SseSigningIT adapted to Plan 02 security layer (bootstrap token + JWT auth)
|
- [Phase 04]: SseSigningIT adapted to Plan 02 security layer (bootstrap token + JWT auth)
|
||||||
|
- [Phase 04]: Added /error to SecurityConfig permitAll for proper Spring Boot error forwarding through security
|
||||||
|
- [Phase 04]: Excluded register and refresh paths from ProtocolVersionInterceptor (auth endpoints not data endpoints)
|
||||||
|
- [Phase 04]: Refresh endpoint in permitAll with self-authentication via refresh token (not JWT access token)
|
||||||
|
|
||||||
### Pending Todos
|
### Pending Todos
|
||||||
|
|
||||||
@@ -123,6 +127,6 @@ None yet.
|
|||||||
|
|
||||||
## Session Continuity
|
## Session Continuity
|
||||||
|
|
||||||
Last session: 2026-03-11T19:29:30Z
|
Last session: 2026-03-11T19:40:20.248Z
|
||||||
Stopped at: Completed 04-03-PLAN.md
|
Stopped at: Completed 04-02-PLAN.md
|
||||||
Resume file: All plans complete
|
Resume file: None
|
||||||
|
|||||||
165
.planning/phases/04-security/04-02-SUMMARY.md
Normal file
165
.planning/phases/04-security/04-02-SUMMARY.md
Normal file
@@ -0,0 +1,165 @@
|
|||||||
|
---
|
||||||
|
phase: 04-security
|
||||||
|
plan: 02
|
||||||
|
subsystem: auth
|
||||||
|
tags: [spring-security, jwt-filter, security-filter-chain, bootstrap-token, refresh-token, stateless-auth]
|
||||||
|
|
||||||
|
# Dependency graph
|
||||||
|
requires:
|
||||||
|
- phase: 04-security
|
||||||
|
provides: "JwtService, Ed25519SigningService, BootstrapTokenValidator, SecurityProperties beans"
|
||||||
|
- phase: 03-agent-registry
|
||||||
|
provides: "AgentRegistryService, AgentRegistrationController, SseConnectionManager, SSE endpoints"
|
||||||
|
provides:
|
||||||
|
- "SecurityFilterChain with stateless JWT authentication and public/protected endpoint split"
|
||||||
|
- "JwtAuthenticationFilter extracting JWT from Authorization header or query param"
|
||||||
|
- "Registration endpoint with bootstrap token validation, JWT + refresh token + public key issuance"
|
||||||
|
- "Refresh endpoint issuing new access JWT from valid refresh token"
|
||||||
|
- "TestSecurityHelper for JWT-authenticated integration tests"
|
||||||
|
affects: [04-03]
|
||||||
|
|
||||||
|
# Tech tracking
|
||||||
|
tech-stack:
|
||||||
|
added: []
|
||||||
|
patterns: [OncePerRequestFilter for JWT extraction, SecurityFilterChain with permitAll/authenticated split, error path permit for proper Spring Boot error forwarding]
|
||||||
|
|
||||||
|
key-files:
|
||||||
|
created:
|
||||||
|
- cameleer3-server-app/src/main/java/com/cameleer3/server/app/security/JwtAuthenticationFilter.java
|
||||||
|
- cameleer3-server-app/src/main/java/com/cameleer3/server/app/security/SecurityConfig.java
|
||||||
|
- cameleer3-server-app/src/test/java/com/cameleer3/server/app/TestSecurityHelper.java
|
||||||
|
- cameleer3-server-app/src/test/java/com/cameleer3/server/app/security/SecurityFilterIT.java
|
||||||
|
- cameleer3-server-app/src/test/java/com/cameleer3/server/app/security/BootstrapTokenIT.java
|
||||||
|
- cameleer3-server-app/src/test/java/com/cameleer3/server/app/security/RegistrationSecurityIT.java
|
||||||
|
- cameleer3-server-app/src/test/java/com/cameleer3/server/app/security/JwtRefreshIT.java
|
||||||
|
modified:
|
||||||
|
- cameleer3-server-app/src/main/java/com/cameleer3/server/app/controller/AgentRegistrationController.java
|
||||||
|
- cameleer3-server-app/src/main/java/com/cameleer3/server/app/config/WebConfig.java
|
||||||
|
- cameleer3-server-app/src/test/java/com/cameleer3/server/app/security/TestSecurityConfig.java
|
||||||
|
- cameleer3-server-app/src/test/java/com/cameleer3/server/app/controller/AgentRegistrationControllerIT.java
|
||||||
|
- cameleer3-server-app/src/test/java/com/cameleer3/server/app/controller/ExecutionControllerIT.java
|
||||||
|
- cameleer3-server-app/src/test/java/com/cameleer3/server/app/controller/DiagramControllerIT.java
|
||||||
|
- cameleer3-server-app/src/test/java/com/cameleer3/server/app/controller/MetricsControllerIT.java
|
||||||
|
- cameleer3-server-app/src/test/java/com/cameleer3/server/app/controller/BackpressureIT.java
|
||||||
|
- cameleer3-server-app/src/test/java/com/cameleer3/server/app/controller/DiagramRenderControllerIT.java
|
||||||
|
- cameleer3-server-app/src/test/java/com/cameleer3/server/app/controller/DetailControllerIT.java
|
||||||
|
- cameleer3-server-app/src/test/java/com/cameleer3/server/app/controller/SearchControllerIT.java
|
||||||
|
- cameleer3-server-app/src/test/java/com/cameleer3/server/app/controller/AgentCommandControllerIT.java
|
||||||
|
- cameleer3-server-app/src/test/java/com/cameleer3/server/app/controller/AgentSseControllerIT.java
|
||||||
|
- cameleer3-server-app/src/test/java/com/cameleer3/server/app/storage/DiagramLinkingIT.java
|
||||||
|
- cameleer3-server-app/src/test/java/com/cameleer3/server/app/storage/IngestionSchemaIT.java
|
||||||
|
- cameleer3-server-app/src/test/java/com/cameleer3/server/app/interceptor/ProtocolVersionIT.java
|
||||||
|
- cameleer3-server-app/src/test/java/com/cameleer3/server/app/controller/ForwardCompatIT.java
|
||||||
|
|
||||||
|
key-decisions:
|
||||||
|
- "Added /error to SecurityConfig permitAll to allow Spring Boot error page forwarding through security"
|
||||||
|
- "Excluded register and refresh paths from ProtocolVersionInterceptor (auth endpoints, not data endpoints)"
|
||||||
|
- "SSE authentication via ?token= query parameter handled transparently by JwtAuthenticationFilter"
|
||||||
|
- "Refresh endpoint in permitAll (uses refresh token for self-authentication, not JWT access token)"
|
||||||
|
|
||||||
|
patterns-established:
|
||||||
|
- "TestSecurityHelper @Component for registering test agents and creating auth headers in ITs"
|
||||||
|
- "Bootstrap token in Authorization: Bearer header for registration (same header format as JWT)"
|
||||||
|
- "SecurityFilterChain permits /error for proper error page rendering in authenticated context"
|
||||||
|
|
||||||
|
requirements-completed: [SECU-01, SECU-02, SECU-05]
|
||||||
|
|
||||||
|
# Metrics
|
||||||
|
duration: 26min
|
||||||
|
completed: 2026-03-11
|
||||||
|
---
|
||||||
|
|
||||||
|
# Phase 4 Plan 02: Security Filter Chain and Endpoint Protection Summary
|
||||||
|
|
||||||
|
**Spring Security filter chain with JWT authentication on all protected endpoints, bootstrap token validation on registration, refresh token flow, and 91 passing tests including 18 new security ITs**
|
||||||
|
|
||||||
|
## Performance
|
||||||
|
|
||||||
|
- **Duration:** 26 min
|
||||||
|
- **Started:** 2026-03-11T19:11:48Z
|
||||||
|
- **Completed:** 2026-03-11T19:38:07Z
|
||||||
|
- **Tasks:** 2
|
||||||
|
- **Files modified:** 25
|
||||||
|
|
||||||
|
## Accomplishments
|
||||||
|
- SecurityFilterChain enforces JWT authentication on all endpoints except health, register, refresh, and docs
|
||||||
|
- JwtAuthenticationFilter extracts JWT from Authorization header or ?token= query param (SSE support)
|
||||||
|
- Registration endpoint requires bootstrap token, returns accessToken + refreshToken + serverPublicKey (Ed25519)
|
||||||
|
- Refresh endpoint issues new access JWT from valid refresh token with agent ID verification
|
||||||
|
- All 15 existing ITs adapted to use JWT authentication via TestSecurityHelper
|
||||||
|
- 4 new security ITs (SecurityFilterIT, BootstrapTokenIT, RegistrationSecurityIT, JwtRefreshIT) with 18 tests
|
||||||
|
|
||||||
|
## Task Commits
|
||||||
|
|
||||||
|
Each task was committed atomically:
|
||||||
|
|
||||||
|
1. **Task 1: SecurityFilterChain + JwtAuthenticationFilter + registration/refresh integration** - `387e2e6` (feat)
|
||||||
|
2. **Task 2: Security integration tests + existing test adaptation** - `539b85f` (test)
|
||||||
|
|
||||||
|
## Files Created/Modified
|
||||||
|
|
||||||
|
- `...security/JwtAuthenticationFilter.java` - OncePerRequestFilter extracting JWT from header or query param
|
||||||
|
- `...security/SecurityConfig.java` - SecurityFilterChain with public/protected endpoint split
|
||||||
|
- `...controller/AgentRegistrationController.java` - Updated with bootstrap token validation, JWT issuance, refresh endpoint
|
||||||
|
- `...config/WebConfig.java` - Excluded register/refresh from ProtocolVersionInterceptor
|
||||||
|
- `...TestSecurityHelper.java` - Test utility for JWT-authenticated requests
|
||||||
|
- `...security/SecurityFilterIT.java` - 6 tests for protected/public endpoint access control
|
||||||
|
- `...security/BootstrapTokenIT.java` - 4 tests for bootstrap token validation on registration
|
||||||
|
- `...security/RegistrationSecurityIT.java` - 3 tests for registration security response
|
||||||
|
- `...security/JwtRefreshIT.java` - 5 tests for refresh token flow
|
||||||
|
- 15 existing IT files updated with JWT authentication headers
|
||||||
|
|
||||||
|
## Decisions Made
|
||||||
|
|
||||||
|
- **Added /error to permitAll:** Spring Boot forwards exceptions to /error endpoint; without permitting it, controllers returning 404 via ResponseStatusException would result in 403 to the client.
|
||||||
|
- **Excluded register/refresh from ProtocolVersionInterceptor:** These are auth/token-renewal endpoints that agents call without full protocol handshake context. Protocol version enforcement is for data/management endpoints.
|
||||||
|
- **Refresh endpoint uses permitAll + self-authentication:** The refresh endpoint validates the refresh token directly rather than requiring a separate JWT access token, simplifying the agent token renewal flow.
|
||||||
|
- **SSE query param authentication transparent:** JwtAuthenticationFilter checks both Authorization header and ?token= query param, so no SSE controller changes needed.
|
||||||
|
|
||||||
|
## Deviations from Plan
|
||||||
|
|
||||||
|
### Auto-fixed Issues
|
||||||
|
|
||||||
|
**1. [Rule 3 - Blocking] Added /error to SecurityConfig permitAll**
|
||||||
|
- **Found during:** Task 2 (test execution)
|
||||||
|
- **Issue:** Controllers using ResponseStatusException(NOT_FOUND) forward to /error endpoint, which was blocked by Spring Security, resulting in 403 instead of 404
|
||||||
|
- **Fix:** Added "/error" to the permitAll requestMatchers list
|
||||||
|
- **Files modified:** SecurityConfig.java
|
||||||
|
- **Verification:** All 91 tests pass, 404 responses correctly returned
|
||||||
|
|
||||||
|
**2. [Rule 3 - Blocking] Excluded register/refresh from ProtocolVersionInterceptor**
|
||||||
|
- **Found during:** Task 2 (JwtRefreshIT tests returning 400)
|
||||||
|
- **Issue:** Refresh endpoint matched /api/v1/agents/** interceptor pattern, rejecting requests without X-Cameleer-Protocol-Version header with 400
|
||||||
|
- **Fix:** Added /api/v1/agents/register and /api/v1/agents/*/refresh to interceptor excludePathPatterns
|
||||||
|
- **Files modified:** WebConfig.java
|
||||||
|
- **Verification:** All JwtRefreshIT and BootstrapTokenIT tests pass
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Total deviations:** 2 auto-fixed (2 blocking)
|
||||||
|
**Impact on plan:** Both fixes necessary for correct Spring Security + Spring MVC interceptor integration. No scope creep.
|
||||||
|
|
||||||
|
## Issues Encountered
|
||||||
|
|
||||||
|
None beyond the auto-fixed blocking issues above.
|
||||||
|
|
||||||
|
## User Setup Required
|
||||||
|
|
||||||
|
None - no external service configuration required.
|
||||||
|
|
||||||
|
## Next Phase Readiness
|
||||||
|
|
||||||
|
- Full Spring Security filter chain active with JWT auth on all protected endpoints
|
||||||
|
- TestSecurityHelper available for all future integration tests
|
||||||
|
- Ready for Plan 03: Ed25519 signing of SSE command payloads
|
||||||
|
- Registration flow complete: bootstrap token -> register -> receive JWT + public key -> use JWT for all API calls -> refresh when expired
|
||||||
|
|
||||||
|
## Self-Check: PASSED
|
||||||
|
|
||||||
|
- All 7 created files verified present on disk
|
||||||
|
- Both commits (387e2e6, 539b85f) verified in git log
|
||||||
|
- Full `mvn clean verify` passed: 91 tests, 0 failures
|
||||||
|
|
||||||
|
---
|
||||||
|
*Phase: 04-security*
|
||||||
|
*Completed: 2026-03-11*
|
||||||
Reference in New Issue
Block a user