From 40364b56380f6dfe4a6e7193e36b7095ab807400 Mon Sep 17 00:00:00 2001 From: LucasX Ubuntu Date: Thu, 9 Apr 2026 16:58:59 +0200 Subject: [PATCH] fix: format --- src/auth/jwt.rs | 22 ++++++----------- src/auth/keycloak.rs | 28 ++++++++++----------- src/auth/middleware.rs | 23 ++++++------------ src/auth/mod.rs | 2 +- src/main.rs | 55 +++++++++++++++++------------------------- 5 files changed, 52 insertions(+), 78 deletions(-) diff --git a/src/auth/jwt.rs b/src/auth/jwt.rs index 21eb32c..d322689 100644 --- a/src/auth/jwt.rs +++ b/src/auth/jwt.rs @@ -1,8 +1,8 @@ -use jsonwebtoken::{decode, decode_header, Algorithm, DecodingKey, Validation}; +use jsonwebtoken::{Algorithm, DecodingKey, Validation, decode, decode_header}; +use once_cell::sync::Lazy; use serde::{Deserialize, Serialize}; use serde_json::Value; use std::env; -use once_cell::sync::Lazy; #[derive(Debug, Deserialize, Serialize, Clone)] pub struct Claims { @@ -19,9 +19,7 @@ pub struct RealmAccess { pub roles: Vec, } -static ISSUER: Lazy = Lazy::new(|| { - env::var("ISSUER").expect("ISSUER not set") -}); +static ISSUER: Lazy = Lazy::new(|| env::var("ISSUER").expect("ISSUER not set")); pub fn validate_token(token: &str, jwks: &Value) -> Result { // 1. Decode header @@ -30,9 +28,7 @@ pub fn validate_token(token: &str, jwks: &Value) -> Result { let kid = header.kid.ok_or("Missing kid")?; // 2. Find matching key - let keys = jwks["keys"] - .as_array() - .ok_or("Invalid JWKS")?; + let keys = jwks["keys"].as_array().ok_or("Invalid JWKS")?; let key = keys .iter() @@ -44,8 +40,7 @@ pub fn validate_token(token: &str, jwks: &Value) -> Result { let e = key["e"].as_str().ok_or("Missing e")?; let decoding_key = - DecodingKey::from_rsa_components(n, e) - .map_err(|_| "Invalid decoding key")?; + DecodingKey::from_rsa_components(n, e).map_err(|_| "Invalid decoding key")?; // 4. Setup validation rules let mut validation = Validation::new(Algorithm::RS256); @@ -57,9 +52,8 @@ pub fn validate_token(token: &str, jwks: &Value) -> Result { validation.validate_aud = false; // depends on your Keycloak config // 5. Decode & verify - let token_data = - decode::(token, &decoding_key, &validation) - .map_err(|_| "Token validation failed")?; + let token_data = decode::(token, &decoding_key, &validation) + .map_err(|_| "Token validation failed")?; Ok(token_data.claims) -} \ No newline at end of file +} diff --git a/src/auth/keycloak.rs b/src/auth/keycloak.rs index 56846f6..f8796af 100644 --- a/src/auth/keycloak.rs +++ b/src/auth/keycloak.rs @@ -1,9 +1,9 @@ -use serde_json::Value; -use std::sync::Arc; -use tokio::sync::RwLock; -use std::time::{Duration, Instant}; -use std::env; use once_cell::sync::Lazy; +use serde_json::Value; +use std::env; +use std::sync::Arc; +use std::time::{Duration, Instant}; +use tokio::sync::RwLock; #[derive(Clone)] struct JwksCache { @@ -11,12 +11,9 @@ struct JwksCache { last_fetched: Instant, } -static JWK_CACHE: Lazy>>> = - Lazy::new(|| Arc::new(RwLock::new(None))); +static JWK_CACHE: Lazy>>> = Lazy::new(|| Arc::new(RwLock::new(None))); -static JWKS_URL: Lazy = Lazy::new(|| { - env::var("JWKS_URL").expect("JWKS_URL not set") -}); +static JWKS_URL: Lazy = Lazy::new(|| env::var("JWKS_URL").expect("JWKS_URL not set")); async fn fetch_jwks() -> Result { let jwks = reqwest::get(JWKS_URL.as_str()) @@ -47,13 +44,14 @@ pub async fn get_jwks() -> Result { // Read lock first (fast path) let read = JWK_CACHE.read().await; - if let Some(cache) = &*read { - if cache.last_fetched.elapsed() < ttl { - return Ok(cache.jwks.clone()); - } + if let Some(cache) = read + .as_ref() + .filter(|cache| cache.last_fetched.elapsed() < ttl) + { + return Ok(cache.jwks.clone()); } } // Expired or empty → refresh refresh_jwks().await -} \ No newline at end of file +} diff --git a/src/auth/middleware.rs b/src/auth/middleware.rs index e9072c3..41ddacf 100644 --- a/src/auth/middleware.rs +++ b/src/auth/middleware.rs @@ -1,25 +1,18 @@ -use axum::{ - extract::Request, - http::{StatusCode}, - middleware::Next, - response::Response, +use axum::{extract::Request, http::StatusCode, middleware::Next, response::Response}; + +use crate::auth::{ + jwt::validate_token, + keycloak::{get_jwks, refresh_jwks}, }; -use crate::auth::{jwt::validate_token, keycloak::{get_jwks, refresh_jwks}}; - -pub async fn auth_middleware( - mut request: Request, - next: Next, -) -> Result { +pub async fn auth_middleware(mut request: Request, next: Next) -> Result { dbg!("Middleware hit"); let headers = request.headers(); dbg!("Headers extracted"); - let auth_header = headers - .get("authorization") - .and_then(|v| v.to_str().ok()); + let auth_header = headers.get("authorization").and_then(|v| v.to_str().ok()); dbg!("Auth header: {:?}", auth_header); @@ -51,4 +44,4 @@ pub async fn auth_middleware( } } } -} \ No newline at end of file +} diff --git a/src/auth/mod.rs b/src/auth/mod.rs index c260d26..2370243 100644 --- a/src/auth/mod.rs +++ b/src/auth/mod.rs @@ -1,3 +1,3 @@ pub mod jwt; pub mod keycloak; -pub mod middleware; \ No newline at end of file +pub mod middleware; diff --git a/src/main.rs b/src/main.rs index ef137e8..56df4be 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,25 +1,17 @@ mod auth; -use crate::auth::middleware::auth_middleware; use crate::auth::jwt::Claims; +use crate::auth::middleware::auth_middleware; -use dotenvy::dotenv; use axum::extract::Extension; -use axum::{ - routing::get, - Router, - middleware, -}; +use axum::{Router, middleware, routing::get}; +use dotenvy::dotenv; use std::net::SocketAddr; -pub async fn protected_route( - Extension(claims): Extension, -) -> String { +pub async fn protected_route(Extension(claims): Extension) -> String { format!( "Hello {}, your user id is {}", - claims - .preferred_username - .unwrap_or("unknown".to_string()), + claims.preferred_username.unwrap_or("unknown".to_string()), claims.sub ) } @@ -30,37 +22,34 @@ pub async fn public_route() -> &'static str { } pub fn app() -> Router { - let public_routes = Router::new() - .route("/", get(public_route)); + let public_routes = Router::new().route("/", get(public_route)); let protected_routes = Router::new() .route("/protected", get(protected_route)) .layer(middleware::from_fn(auth_middleware)); - Router::new() - .merge(public_routes) - .merge(protected_routes) + Router::new().merge(public_routes).merge(protected_routes) } #[tokio::main] async fn main() { - dotenv().ok(); + dotenv().ok(); -// let jwks = keycloak::get_jwks() -// .await -// .expect("Failed to fetch JWKS"); + // let jwks = keycloak::get_jwks() + // .await + // .expect("Failed to fetch JWKS"); -// // println!("{:?}", jwks); + // // println!("{:?}", jwks); -// let token = "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJublpLek04TkZHVmpWbGFPRXZpMUtFSTVHQWRwaGlsYjh3RHRLeG5JOENZIn0.eyJleHAiOjE3NzU3Mzg2MDUsImlhdCI6MTc3NTczODMwNSwianRpIjoiNjk2OTY4NzQtZWMwNi00NGFkLTg0MDYtYmY3YWM4MjI5MjkxIiwiaXNzIjoiaHR0cHM6Ly9hdXRoLmljZWJlcmcuYmxhY2svcmVhbG1zL2ljZWJlcmciLCJzdWIiOiJmZGRiN2FjZC1kMmE5LTRmMTctOWIxNi1kZjVlN2EzNDI4YjciLCJ0eXAiOiJCZWFyZXIiLCJhenAiOiJjaGF0LWFwaSIsInNjb3BlIjoiIiwiY2xpZW50SG9zdCI6Ijg2LjIxMi44NC4xOTEiLCJjbGllbnRBZGRyZXNzIjoiODYuMjEyLjg0LjE5MSIsImNsaWVudF9pZCI6ImNoYXQtYXBpIn0.BS7ohLWiMDxAUz_Q-Qi2UoLYbNn8AUrYeSWeO-602SQ-AYBW3gfYxXOSeRgWyn4VfObpVfK7QfqQBUxorXxi1JVld-4fGXL8NXQNyq5Ip_JHNG1p02Z39Pe9MmC9MXOwA_GQF2PIkLIdOJ_W_guXVhl2ptEWPPSiXM5Z5CNg8lyOiKPI0g2JWV6FBRG-HMXzqnxAb1j8wGUpC9JzGwAU3sjWBGhT1AAovs-XLmm5hZEPxI-Ia3SmUnF-QjFMmebPVxLdxL7OszzVEhKipsZRiwQxjY6eJhJFFa8uycBigHPSzu_HqqkK6AjNlyExvR0EGvl9zUWdOfMPDiVX2Sg92g"; -// match jwt::validate_token(token, &jwks) { -// Ok(claims) => { -// println!("Valid token for user: {:?}", claims); -// } -// Err(err) => { -// println!("Invalid token: {}", err); -// } -// } + // let token = "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJublpLek04TkZHVmpWbGFPRXZpMUtFSTVHQWRwaGlsYjh3RHRLeG5JOENZIn0.eyJleHAiOjE3NzU3Mzg2MDUsImlhdCI6MTc3NTczODMwNSwianRpIjoiNjk2OTY4NzQtZWMwNi00NGFkLTg0MDYtYmY3YWM4MjI5MjkxIiwiaXNzIjoiaHR0cHM6Ly9hdXRoLmljZWJlcmcuYmxhY2svcmVhbG1zL2ljZWJlcmciLCJzdWIiOiJmZGRiN2FjZC1kMmE5LTRmMTctOWIxNi1kZjVlN2EzNDI4YjciLCJ0eXAiOiJCZWFyZXIiLCJhenAiOiJjaGF0LWFwaSIsInNjb3BlIjoiIiwiY2xpZW50SG9zdCI6Ijg2LjIxMi44NC4xOTEiLCJjbGllbnRBZGRyZXNzIjoiODYuMjEyLjg0LjE5MSIsImNsaWVudF9pZCI6ImNoYXQtYXBpIn0.BS7ohLWiMDxAUz_Q-Qi2UoLYbNn8AUrYeSWeO-602SQ-AYBW3gfYxXOSeRgWyn4VfObpVfK7QfqQBUxorXxi1JVld-4fGXL8NXQNyq5Ip_JHNG1p02Z39Pe9MmC9MXOwA_GQF2PIkLIdOJ_W_guXVhl2ptEWPPSiXM5Z5CNg8lyOiKPI0g2JWV6FBRG-HMXzqnxAb1j8wGUpC9JzGwAU3sjWBGhT1AAovs-XLmm5hZEPxI-Ia3SmUnF-QjFMmebPVxLdxL7OszzVEhKipsZRiwQxjY6eJhJFFa8uycBigHPSzu_HqqkK6AjNlyExvR0EGvl9zUWdOfMPDiVX2Sg92g"; + // match jwt::validate_token(token, &jwks) { + // Ok(claims) => { + // println!("Valid token for user: {:?}", claims); + // } + // Err(err) => { + // println!("Invalid token: {}", err); + // } + // } let app = app(); let addr = SocketAddr::from(([127, 0, 0, 1], 3000)); @@ -69,4 +58,4 @@ async fn main() { axum::serve(tokio::net::TcpListener::bind(addr).await.unwrap(), app) .await .unwrap(); -} \ No newline at end of file +}