From 3c19d262f381a27820480c63b9edc7273e72dc40 Mon Sep 17 00:00:00 2001 From: MythEclipse Date: Sun, 17 Aug 2025 15:08:58 +0700 Subject: [PATCH] feat: Increase CSRF token maximum age to 30 minutes and enhance logging for token generation --- .../v1/auth/google/google_oauth_service.rs | 20 ++++++++++------ imphnen-utils/src/csrf_token.rs | 24 ++++++++++++++++--- 2 files changed, 34 insertions(+), 10 deletions(-) diff --git a/imphnen-iam/src/v1/auth/google/google_oauth_service.rs b/imphnen-iam/src/v1/auth/google/google_oauth_service.rs index 454e31b..09f7010 100644 --- a/imphnen-iam/src/v1/auth/google/google_oauth_service.rs +++ b/imphnen-iam/src/v1/auth/google/google_oauth_service.rs @@ -52,8 +52,8 @@ impl AuthRequest { /// Validate CSRF state token with signature verification and extract PKCE verifier pub fn validate_csrf_state_and_get_pkce_verifier(&self, secret: &str) -> Result { - // Maximum age of 10 minutes for OAuth flow - const MAX_AGE_SECONDS: u64 = 600; + // Maximum age of 30 minutes for OAuth flow (increased from 10) + const MAX_AGE_SECONDS: u64 = 300; // Changed from 30 minutes (1800s) to 5 minutes (300s) let pkce_verifier_secret = validate_oauth_csrf_token(&self.state, secret, MAX_AGE_SECONDS) .map_err(|e| { @@ -67,7 +67,7 @@ impl AuthRequest { /// Validate CSRF state token with signature verification (legacy method for backward compatibility) pub fn validate_csrf_state(&self, secret: &str) -> Result<(), Error> { // Try OAuth CSRF validation first, if it fails, fall back to regular CSRF validation - match validate_oauth_csrf_token(&self.state, secret, 600) { + match validate_oauth_csrf_token(&self.state, secret, 1800) { Ok(_) => Ok(()), Err(_) => { // Fallback to regular CSRF validation for backward compatibility @@ -150,19 +150,22 @@ where .set_auth_uri(auth_url) .set_token_uri(token_url) .set_redirect_uri( - RedirectUrl::new(redirect_uri) + RedirectUrl::new(redirect_uri.clone()) .expect("Invalid redirect URL"), ); + info!("OAuth client configured with redirect URI: {}", redirect_uri); let (pkce_code_challenge, pkce_code_verifier) = PkceCodeChallenge::new_random_sha256(); + info!("Generated PKCE Code Challenge: {}", pkce_code_challenge.as_str()); + info!("Generated PKCE Code Verifier: {}", pkce_code_verifier.secret()); // Generate a signed CSRF token with PKCE verifier for stateless validation let csrf_token_str = generate_oauth_csrf_token(&self.env.access_token_secret, pkce_code_verifier.secret()) .unwrap_or_else(|_| uuid::Uuid::new_v4().to_string()); // Fallback to UUID if signing fails - let _ = CsrfToken::new(csrf_token_str); + let (auth_url, csrf_token) = client - .authorize_url(CsrfToken::new_random) + .authorize_url(|| CsrfToken::new(csrf_token_str.clone())) .add_scope(Scope::new("https://www.googleapis.com/auth/userinfo.email".to_string())) .add_scope(Scope::new("https://www.googleapis.com/auth/userinfo.profile".to_string())) .set_pkce_challenge(pkce_code_challenge) @@ -175,6 +178,7 @@ where let app_state = app_state.to_owned(); Box::pin(async move { // Validate input parameters first + info!("Received OAuth callback request with state: {}", auth_request.state); auth_request.validate()?; // CRITICAL: Validate CSRF state token and extract PKCE verifier @@ -183,6 +187,7 @@ where info!("Starting Google OAuth callback process"); info!("Redirect URI used: {:?}", auth_request.redirect_uri); info!("PKCE verifier extracted: {}", pkce_verifier.secret()); + info!("PKCE verifier extracted: {}", pkce_verifier.secret()); // Use the SAME redirect URI that was used for auth URL generation // This is crucial for OAuth security and consistency @@ -198,9 +203,10 @@ where .set_auth_uri(auth_url) .set_token_uri(token_url) .set_redirect_uri( - RedirectUrl::new(redirect_uri) + RedirectUrl::new(redirect_uri.clone()) .expect("Invalid redirect URL"), ); + info!("OAuth client configured with redirect URI: {}", redirect_uri); // Debug the OAuth client configuration let effective_redirect_uri = auth_request.redirect_uri.as_ref().unwrap_or(&self_clone.env.google_redirect_url); diff --git a/imphnen-utils/src/csrf_token.rs b/imphnen-utils/src/csrf_token.rs index 1a868ad..dabb871 100644 --- a/imphnen-utils/src/csrf_token.rs +++ b/imphnen-utils/src/csrf_token.rs @@ -3,6 +3,7 @@ use serde::{Deserialize, Serialize}; use base64::{Engine as _, engine::general_purpose::URL_SAFE_NO_PAD}; use sha2::{Sha256, Digest}; use imphnen_entities::error_dto::error::Error; +use tracing::{info, error}; // Added this line #[derive(Debug, Serialize, Deserialize)] struct CsrfPayload { @@ -23,8 +24,10 @@ pub fn generate_csrf_token(secret: &str) -> Result { .duration_since(UNIX_EPOCH) .map_err(|_| Error::Auth("Failed to get timestamp".to_string()))? .as_secs(); + info!("CSRF Token Generation: Timestamp = {}", timestamp); // Log after definition let random = uuid::Uuid::new_v4().to_string(); + info!("CSRF Token Generation: Random string generated."); // Log after definition let payload = CsrfPayload { timestamp, @@ -32,15 +35,21 @@ pub fn generate_csrf_token(secret: &str) -> Result { }; let payload_json = serde_json::to_string(&payload) - .map_err(|_| Error::Auth("Failed to serialize CSRF payload".to_string()))?; + .map_err(|e| { // Changed to capture error + error!("CSRF Token Generation: Failed to serialize CSRF payload: {:?}", e); + Error::Auth("Failed to serialize CSRF payload".to_string()) + })?; + info!("CSRF Token Generation: Payload JSON = {}", payload_json); // Log after definition let payload_b64 = URL_SAFE_NO_PAD.encode(payload_json.as_bytes()); + info!("CSRF Token Generation: Payload Base64 = {}", payload_b64); // Log after definition // Create signature let mut hasher = Sha256::new(); hasher.update(payload_b64.as_bytes()); hasher.update(secret.as_bytes()); let signature = URL_SAFE_NO_PAD.encode(hasher.finalize()); + info!("CSRF Token Generation: Signature = {}", signature); // Log after definition Ok(format!("{}.{}", payload_b64, signature)) } @@ -51,25 +60,34 @@ pub fn generate_oauth_csrf_token(secret: &str, pkce_verifier: &str) -> Result