Rename Java packages from com.cameleer3 to com.cameleer, module directories from cameleer3-* to cameleer-*, and all references throughout workflows, Dockerfiles, docs, migrations, and pom.xml. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
166 lines
9.1 KiB
Markdown
166 lines
9.1 KiB
Markdown
---
|
|
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:
|
|
- cameleer-server-app/src/main/java/com/cameleer/server/app/security/JwtAuthenticationFilter.java
|
|
- cameleer-server-app/src/main/java/com/cameleer/server/app/security/SecurityConfig.java
|
|
- cameleer-server-app/src/test/java/com/cameleer/server/app/TestSecurityHelper.java
|
|
- cameleer-server-app/src/test/java/com/cameleer/server/app/security/SecurityFilterIT.java
|
|
- cameleer-server-app/src/test/java/com/cameleer/server/app/security/BootstrapTokenIT.java
|
|
- cameleer-server-app/src/test/java/com/cameleer/server/app/security/RegistrationSecurityIT.java
|
|
- cameleer-server-app/src/test/java/com/cameleer/server/app/security/JwtRefreshIT.java
|
|
modified:
|
|
- cameleer-server-app/src/main/java/com/cameleer/server/app/controller/AgentRegistrationController.java
|
|
- cameleer-server-app/src/main/java/com/cameleer/server/app/config/WebConfig.java
|
|
- cameleer-server-app/src/test/java/com/cameleer/server/app/security/TestSecurityConfig.java
|
|
- cameleer-server-app/src/test/java/com/cameleer/server/app/controller/AgentRegistrationControllerIT.java
|
|
- cameleer-server-app/src/test/java/com/cameleer/server/app/controller/ExecutionControllerIT.java
|
|
- cameleer-server-app/src/test/java/com/cameleer/server/app/controller/DiagramControllerIT.java
|
|
- cameleer-server-app/src/test/java/com/cameleer/server/app/controller/MetricsControllerIT.java
|
|
- cameleer-server-app/src/test/java/com/cameleer/server/app/controller/BackpressureIT.java
|
|
- cameleer-server-app/src/test/java/com/cameleer/server/app/controller/DiagramRenderControllerIT.java
|
|
- cameleer-server-app/src/test/java/com/cameleer/server/app/controller/DetailControllerIT.java
|
|
- cameleer-server-app/src/test/java/com/cameleer/server/app/controller/SearchControllerIT.java
|
|
- cameleer-server-app/src/test/java/com/cameleer/server/app/controller/AgentCommandControllerIT.java
|
|
- cameleer-server-app/src/test/java/com/cameleer/server/app/controller/AgentSseControllerIT.java
|
|
- cameleer-server-app/src/test/java/com/cameleer/server/app/storage/DiagramLinkingIT.java
|
|
- cameleer-server-app/src/test/java/com/cameleer/server/app/storage/IngestionSchemaIT.java
|
|
- cameleer-server-app/src/test/java/com/cameleer/server/app/interceptor/ProtocolVersionIT.java
|
|
- cameleer-server-app/src/test/java/com/cameleer/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*
|