docs(04-02): complete security filter chain wiring plan

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
hsiegeln
2026-03-11 20:40:33 +01:00
parent 539b85f307
commit acf78a10f1
3 changed files with 181 additions and 12 deletions

View 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*