fix: agent auth, heartbeat, and SSE all break after server restart
Three related issues caused by in-memory agent registry being empty after server restart: 1. JwtAuthenticationFilter rejected valid agent JWTs if agent wasn't in registry — now authenticates any valid JWT regardless 2. Heartbeat returned 404 for unknown agents — now auto-registers the agent from JWT claims (subject, application) 3. SSE endpoint returned 404 — same auto-registration fix JWT validation result is stored as a request attribute so downstream controllers can extract the application claim for auto-registration. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -32,6 +32,7 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(JwtAuthenticationFilter.class);
|
||||
private static final String BEARER_PREFIX = "Bearer ";
|
||||
public static final String JWT_RESULT_ATTR = "cameleer.jwt.result";
|
||||
|
||||
private final JwtService jwtService;
|
||||
private final AgentRegistryService agentRegistryService;
|
||||
@@ -52,25 +53,17 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter {
|
||||
JwtValidationResult result = jwtService.validateAccessToken(token);
|
||||
String subject = result.subject();
|
||||
|
||||
if (subject.startsWith("user:")) {
|
||||
// UI user token — authenticate with roles from JWT
|
||||
List<GrantedAuthority> authorities = toAuthorities(result.roles());
|
||||
UsernamePasswordAuthenticationToken auth =
|
||||
new UsernamePasswordAuthenticationToken(subject, null, authorities);
|
||||
SecurityContextHolder.getContext().setAuthentication(auth);
|
||||
} else if (agentRegistryService.findById(subject) != null) {
|
||||
// Agent token — use roles from JWT, default to AGENT if empty
|
||||
List<String> roles = result.roles();
|
||||
if (roles.isEmpty()) {
|
||||
roles = List.of("AGENT");
|
||||
}
|
||||
List<GrantedAuthority> authorities = toAuthorities(roles);
|
||||
UsernamePasswordAuthenticationToken auth =
|
||||
new UsernamePasswordAuthenticationToken(subject, null, authorities);
|
||||
SecurityContextHolder.getContext().setAuthentication(auth);
|
||||
} else {
|
||||
log.debug("JWT valid but agent not found: {}", subject);
|
||||
// Authenticate any valid JWT — agent registry is not authoritative
|
||||
// (agents may hold valid tokens after server restart clears the in-memory registry)
|
||||
List<String> roles = result.roles();
|
||||
if (!subject.startsWith("user:") && roles.isEmpty()) {
|
||||
roles = List.of("AGENT");
|
||||
}
|
||||
List<GrantedAuthority> authorities = toAuthorities(roles);
|
||||
UsernamePasswordAuthenticationToken auth =
|
||||
new UsernamePasswordAuthenticationToken(subject, null, authorities);
|
||||
SecurityContextHolder.getContext().setAuthentication(auth);
|
||||
request.setAttribute(JWT_RESULT_ATTR, result);
|
||||
} catch (Exception e) {
|
||||
log.debug("JWT validation failed: {}", e.getMessage());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user