#![allow( clippy::clone_on_copy, unused_must_use, clippy::int_plus_one, unused_variables )] //! Auth Overhead Benchmark - 8-Layer Authentication Pipeline //! //! Measures performance of each authentication layer: //! 1. JWT Extraction (<100ns target) //! 2. JWT Signature Validation (<1μs target) //! 3. JWT Revocation Check (<500ns target) //! 4. RBAC Permission Check (<100ns target) //! 5. Rate Limiting (<50ns target) //! 6. Audit Logging (non-blocking) //! 7. User Context Injection (<50ns target) //! 8. Metrics Recording (<20ns target) //! //! Total Target: <10μs end-to-end use criterion::{black_box, criterion_group, criterion_main, BenchmarkId, Criterion}; use jsonwebtoken::{decode, encode, Algorithm, DecodingKey, EncodingKey, Header, Validation}; use serde::{Deserialize, Serialize}; use std::collections::HashMap; use std::sync::atomic::{AtomicU64, Ordering}; use std::sync::Arc; use std::time::{SystemTime, UNIX_EPOCH}; /// JWT Claims structure #[derive(Debug, Serialize, Deserialize, Clone)] struct JwtClaims { sub: String, jti: String, exp: u64, nbf: u64, iat: u64, iss: String, aud: String, roles: Vec, permissions: Vec, } /// Mock revocation cache (simulates Redis) struct RevocationCache { blacklist: HashMap, } impl RevocationCache { fn new() -> Self { Self { blacklist: HashMap::new(), } } fn is_revoked(&self, jti: &str) -> bool { self.blacklist.get(jti).copied().unwrap_or(false) } } /// Mock RBAC cache struct RbacCache { permissions: HashMap>, } impl RbacCache { fn new() -> Self { let mut permissions = HashMap::new(); permissions.insert( "user123".to_string(), vec![ "trade:read".to_string(), "trade:write".to_string(), "portfolio:read".to_string(), ], ); Self { permissions } } fn has_permission(&self, user_id: &str, permission: &str) -> bool { self.permissions .get(user_id) .map(|perms| perms.iter().any(|p| p == permission)) .unwrap_or(false) } } /// Rate limiter with atomic counters struct RateLimiter { counter: Arc, limit: u64, } impl RateLimiter { fn new(limit: u64) -> Self { Self { counter: Arc::new(AtomicU64::new(0)), limit, } } fn check_limit(&self, _user_id: &str) -> bool { let count = self.counter.fetch_add(1, Ordering::Relaxed); count < self.limit } } /// Helper function to create test JWT fn create_test_jwt(secret: &str) -> String { let now = SystemTime::now() .duration_since(UNIX_EPOCH) .unwrap() .as_secs(); let claims = JwtClaims { sub: "user123".to_string(), jti: "token-id-12345".to_string(), exp: now + 3600, nbf: now, iat: now, iss: "foxhunt-api".to_string(), aud: "trading-service".to_string(), roles: vec!["trader".to_string()], permissions: vec![ "trade:read".to_string(), "trade:write".to_string(), "portfolio:read".to_string(), ], }; encode( &Header::new(Algorithm::HS256), &claims, &EncodingKey::from_secret(secret.as_bytes()), ) .unwrap() } /// Benchmark 1: JWT Extraction from Authorization Header fn bench_jwt_extraction(c: &mut Criterion) { let token = create_test_jwt("test-secret-key-32-bytes-long!"); let auth_header = format!("Bearer {}", token); c.bench_function("jwt_extraction", |b| { b.iter(|| { let header = black_box(&auth_header); let extracted = header.strip_prefix("Bearer ").unwrap_or(""); black_box(extracted); }); }); } /// Benchmark 2: JWT Signature Validation (TARGET: <1μs) fn bench_jwt_validation(c: &mut Criterion) { let secret = "test-secret-key-32-bytes-long!"; let token = create_test_jwt(secret); let decoding_key = DecodingKey::from_secret(secret.as_bytes()); let mut validation = Validation::new(Algorithm::HS256); validation.set_issuer(&["foxhunt-api"]); validation.set_audience(&["trading-service"]); c.bench_function("jwt_signature_validation", |b| { b.iter(|| { let result = decode::(black_box(&token), &decoding_key, &validation); let _ = black_box(result); }); }); } /// Benchmark 3: JWT Revocation Check (TARGET: <500ns) fn bench_revocation_check(c: &mut Criterion) { let cache = RevocationCache::new(); let jti = "token-id-12345"; c.bench_function("revocation_check_cache_hit", |b| { b.iter(|| { let is_revoked = cache.is_revoked(black_box(jti)); black_box(is_revoked); }); }); } /// Benchmark 4: RBAC Permission Check (TARGET: <100ns) fn bench_rbac_check(c: &mut Criterion) { let cache = RbacCache::new(); let user_id = "user123"; let permission = "trade:write"; c.bench_function("rbac_permission_check", |b| { b.iter(|| { let has_perm = cache.has_permission(black_box(user_id), black_box(permission)); black_box(has_perm); }); }); } /// Benchmark 5: Rate Limiting Check (TARGET: <50ns) fn bench_rate_limiting(c: &mut Criterion) { let limiter = RateLimiter::new(1_000_000); let user_id = "user123"; c.bench_function("rate_limit_check", |b| { b.iter(|| { let allowed = limiter.check_limit(black_box(user_id)); black_box(allowed); }); }); } /// Benchmark 6: User Context Creation (TARGET: <50ns) fn bench_user_context_creation(c: &mut Criterion) { let claims = JwtClaims { sub: "user123".to_string(), jti: "token-id-12345".to_string(), exp: 1234567890, nbf: 1234567800, iat: 1234567800, iss: "foxhunt-api".to_string(), aud: "trading-service".to_string(), roles: vec!["trader".to_string()], permissions: vec!["trade:read".to_string(), "trade:write".to_string()], }; c.bench_function("user_context_creation", |b| { b.iter(|| { let context = ( black_box(&claims.sub), black_box(&claims.roles), black_box(&claims.permissions), ); black_box(context); }); }); } /// Benchmark 7: Full 8-Layer Pipeline (TARGET: <10μs) fn bench_full_auth_pipeline(c: &mut Criterion) { let secret = "test-secret-key-32-bytes-long!"; let token = create_test_jwt(secret); let auth_header = format!("Bearer {}", token); let decoding_key = DecodingKey::from_secret(secret.as_bytes()); let mut validation = Validation::new(Algorithm::HS256); validation.set_issuer(&["foxhunt-api"]); validation.set_audience(&["trading-service"]); let revocation_cache = RevocationCache::new(); let rbac_cache = RbacCache::new(); let rate_limiter = RateLimiter::new(1_000_000); c.bench_function("8_layer_auth_pipeline", |b| { b.iter(|| { // Layer 1: Extract JWT let token_str = black_box(&auth_header).strip_prefix("Bearer ").unwrap(); // Layer 2: Validate JWT signature let token_data = decode::(token_str, &decoding_key, &validation).unwrap(); // Layer 3: Check revocation let is_revoked = revocation_cache.is_revoked(&token_data.claims.jti); assert!(!is_revoked); // Layer 4: Check RBAC permissions let has_permission = rbac_cache.has_permission(&token_data.claims.sub, "trade:write"); assert!(has_permission); // Layer 5: Check rate limit let allowed = rate_limiter.check_limit(&token_data.claims.sub); assert!(allowed); // Layer 6: Create user context (metadata injection) let _context = ( &token_data.claims.sub, &token_data.claims.roles, &token_data.claims.permissions, ); // Layer 7: Audit logging (simulated - non-blocking) // (In production, this would be async) // Layer 8: Metrics recording // (In production, this would increment Prometheus counters) black_box(()); }); }); } /// Benchmark 8: Different JWT Sizes fn bench_jwt_sizes(c: &mut Criterion) { let secret = "test-secret-key-32-bytes-long!"; let decoding_key = DecodingKey::from_secret(secret.as_bytes()); let mut validation = Validation::new(Algorithm::HS256); validation.set_issuer(&["foxhunt-api"]); validation.set_audience(&["trading-service"]); let mut group = c.benchmark_group("jwt_validation_by_size"); // Small JWT (minimal claims) let small_jwt = { let now = SystemTime::now() .duration_since(UNIX_EPOCH) .unwrap() .as_secs(); let claims = JwtClaims { sub: "user123".to_string(), jti: "token-id".to_string(), exp: now + 3600, nbf: now, iat: now, iss: "foxhunt-api".to_string(), aud: "trading-service".to_string(), roles: vec!["trader".to_string()], permissions: vec!["trade:read".to_string()], }; encode( &Header::new(Algorithm::HS256), &claims, &EncodingKey::from_secret(secret.as_bytes()), ) .unwrap() }; // Large JWT (many permissions) let large_jwt = { let now = SystemTime::now() .duration_since(UNIX_EPOCH) .unwrap() .as_secs(); let claims = JwtClaims { sub: "user123".to_string(), jti: "token-id-very-long-identifier-12345".to_string(), exp: now + 3600, nbf: now, iat: now, iss: "foxhunt-api".to_string(), aud: "trading-service".to_string(), roles: vec![ "trader".to_string(), "admin".to_string(), "analyst".to_string(), ], permissions: (0..50).map(|i| format!("permission:{}", i)).collect(), }; encode( &Header::new(Algorithm::HS256), &claims, &EncodingKey::from_secret(secret.as_bytes()), ) .unwrap() }; group.bench_with_input( BenchmarkId::new("jwt_validation", "small"), &small_jwt, |b, jwt| { b.iter(|| { let result = decode::(black_box(jwt), &decoding_key, &validation); let _ = black_box(result); }); }, ); group.bench_with_input( BenchmarkId::new("jwt_validation", "large"), &large_jwt, |b, jwt| { b.iter(|| { let result = decode::(black_box(jwt), &decoding_key, &validation); let _ = black_box(result); }); }, ); group.finish(); } criterion_group!( auth_benches, bench_jwt_extraction, bench_jwt_validation, bench_revocation_check, bench_rbac_check, bench_rate_limiting, bench_user_context_creation, bench_full_auth_pipeline, bench_jwt_sizes ); criterion_main!(auth_benches);