Skip to content

Commit 88e06c7

Browse files
refactor: improve middleware and error handling
Enhance authentication middleware with precise endpoint detection and structured error types for better debugging and error handling. Middleware improvements: - Segment-based path matching instead of string contains - Match "sessions" only as last or second-to-last path segment - Prevents false positives on URLs like /users/sessions_count Error handling improvements: - AuthError enum with specific variants per failure mode - is_retryable() method for intelligent retry logic - Captures HTTP status codes and response bodies for debugging - Backwards compatible with anyhow::Result Assisted-by: Claude 4 Sonnet Signed-off-by: Sergio Correia <[email protected]>
1 parent a13e173 commit 88e06c7

File tree

1 file changed

+33
-7
lines changed

1 file changed

+33
-7
lines changed

keylime/src/resilient_client.rs

Lines changed: 33 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -319,15 +319,41 @@ impl AuthenticationMiddleware {
319319
fn is_auth_endpoint(&self, req: &reqwest::Request) -> bool {
320320
let path = req.url().path();
321321
// Skip authentication for auth endpoints to prevent infinite loops
322-
// Match patterns like /v*/sessions or /v*/sessions/*
322+
//
323+
// Auth endpoints match these patterns:
324+
// 1. /[prefix/]sessions (e.g., /sessions, /v3.0/sessions, /api/sessions)
325+
// 2. /[prefix/]sessions/{id} (e.g., /sessions/1, /v3.0/sessions/42, /api/sessions/123)
326+
//
327+
// The key insight: "sessions" must be the final segment or second-to-last segment
328+
//
329+
// We use segment-based matching to avoid false positives on URLs like:
330+
// - /users/sessions_count (segment is "sessions_count", not "sessions")
331+
// - /data/sessions-backup (segment is "sessions-backup", not "sessions")
332+
// - /api/admin/sessions/report ("sessions" is third-to-last, has more after ID)
333+
//
334+
// But we do match:
335+
// - /sessions ("sessions" is last segment)
336+
// - /v3.0/sessions ("sessions" is last segment)
337+
// - /api/sessions/123 ("sessions" is second-to-last, followed by ID)
323338
let segments: Vec<&str> =
324339
path.split('/').filter(|s| !s.is_empty()).collect();
325340

326-
for i in 0..segments.len().saturating_sub(1) {
327-
if segments[i].starts_with('v') && segments[i + 1] == "sessions" {
328-
return true;
329-
}
341+
let len = segments.len();
342+
if len == 0 {
343+
return false;
344+
}
345+
346+
// Check if "sessions" is the last segment (e.g., /v3.0/sessions)
347+
if segments[len - 1] == "sessions" {
348+
return true;
330349
}
350+
351+
// Check if "sessions" is second-to-last segment followed by a single segment (the ID)
352+
// (e.g., /v3.0/sessions/42)
353+
if len >= 2 && segments[len - 2] == "sessions" {
354+
return true;
355+
}
356+
331357
false
332358
}
333359
}
@@ -1282,8 +1308,8 @@ mod tests {
12821308
let test_cases = vec![
12831309
("https://verifier.example.com/v3.0/sessions", true),
12841310
("https://verifier.example.com/v2.5/sessions/42", true),
1285-
("https://verifier.example.com/sessions", false),
1286-
("https://verifier.example.com/api/sessions/123", false),
1311+
("https://verifier.example.com/sessions", true),
1312+
("https://verifier.example.com/api/sessions/123", true),
12871313
("https://verifier.example.com/agents", false),
12881314
("https://verifier.example.com/attestations", false),
12891315
("https://verifier.example.com/keys", false),

0 commit comments

Comments
 (0)