Files
cameleer-server/.planning/phases/04-security/04-02-SUMMARY.md
hsiegeln cb3ebfea7c
Some checks failed
CI / cleanup-branch (push) Has been skipped
CI / build (push) Failing after 18s
CI / docker (push) Has been skipped
CI / deploy (push) Has been skipped
CI / deploy-feature (push) Has been skipped
chore: rename cameleer3 to cameleer
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>
2026-04-15 15:28:42 +02:00

9.1 KiB

phase, plan, subsystem, tags, requires, provides, affects, tech-stack, key-files, key-decisions, patterns-established, requirements-completed, duration, completed
phase plan subsystem tags requires provides affects tech-stack key-files key-decisions patterns-established requirements-completed duration completed
04-security 02 auth
spring-security
jwt-filter
security-filter-chain
bootstrap-token
refresh-token
stateless-auth
phase provides
04-security JwtService, Ed25519SigningService, BootstrapTokenValidator, SecurityProperties beans
phase provides
03-agent-registry AgentRegistryService, AgentRegistrationController, SseConnectionManager, SSE endpoints
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
04-03
added patterns
OncePerRequestFilter for JWT extraction
SecurityFilterChain with permitAll/authenticated split
error path permit for proper Spring Boot error forwarding
created modified
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
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
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)
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
SECU-01
SECU-02
SECU-05
26min 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