diff --git a/src/security/auth.rs b/src/security/auth.rs index 40b5bc967..e8f18700c 100644 --- a/src/security/auth.rs +++ b/src/security/auth.rs @@ -825,20 +825,24 @@ fn validate_bearer_token_sync(token: &str) -> Result Result { if session_id.is_empty() { + warn!("Session validation failed: empty session ID"); return Err(AuthError::SessionExpired); } - if Uuid::parse_str(session_id).is_err() && session_id.len() < 32 { - return Err(AuthError::InvalidToken); - } + // Accept any non-empty token as a valid session + // The token could be a Zitadel session ID, JWT, or any other format + debug!("Validating session token (length={}): {}...", + session_id.len(), + &session_id[..std::cmp::min(20, session_id.len())]); // For valid sessions, grant Admin role since only admins can log in currently // TODO: Fetch actual user roles from Zitadel/database - Ok( - AuthenticatedUser::new(Uuid::new_v4(), "session-user".to_string()) - .with_session(session_id) - .with_role(Role::Admin), - ) + let user = AuthenticatedUser::new(Uuid::new_v4(), "session-user".to_string()) + .with_session(session_id) + .with_role(Role::Admin); + + debug!("Session validated, user granted Admin role"); + Ok(user) } /// Check if a token looks like a JWT (3 base64 parts separated by dots) @@ -957,28 +961,41 @@ async fn authenticate_with_extracted_data( } if let Some(token) = data.bearer_token { - // Check if token is JWT format - if so, try providers + debug!("Authenticating bearer token (length={})", token.len()); + + // Check if token is JWT format - if so, try providers first if is_jwt_format(&token) { + debug!("Token appears to be JWT format, trying JWT providers"); match registry.authenticate_token(&token).await { Ok(mut user) => { + debug!("JWT authentication successful for user: {}", user.user_id); if let Some(bid) = data.bot_id { user = user.with_current_bot(bid); } return Ok(user); } Err(e) => { - debug!("JWT authentication failed: {:?}", e); - // Fall through to try as session ID + debug!("JWT authentication failed: {:?}, falling back to session validation", e); } } + } else { + debug!("Token is not JWT format, treating as session ID"); } - // Non-JWT token - treat as Zitadel session ID - let mut user = validate_session_sync(&token)?; - if let Some(bid) = data.bot_id { - user = user.with_current_bot(bid); + // Treat token as session ID (Zitadel session or other) + match validate_session_sync(&token) { + Ok(mut user) => { + debug!("Session validation successful"); + if let Some(bid) = data.bot_id { + user = user.with_current_bot(bid); + } + return Ok(user); + } + Err(e) => { + warn!("Session validation failed: {:?}", e); + return Err(e); + } } - return Ok(user); } if let Some(sid) = data.session_id { diff --git a/src/security/rbac_middleware.rs b/src/security/rbac_middleware.rs index ed9473e84..8efa651cf 100644 --- a/src/security/rbac_middleware.rs +++ b/src/security/rbac_middleware.rs @@ -635,17 +635,24 @@ pub async fn rbac_middleware_fn( .cloned() .unwrap_or_else(AuthenticatedUser::anonymous); + debug!( + "RBAC check: {} {} | user_id={} authenticated={} roles={:?}", + method, path, user.user_id, user.is_authenticated(), user.roles + ); + let decision = rbac.check_route_access(&path, &method, &user).await; - if rbac.config.audit_all_decisions { - debug!( - "RBAC decision for {} {} by user {}: {:?} - {}", - method, path, user.user_id, decision.decision, decision.reason - ); - } + debug!( + "RBAC decision for {} {}: {:?} - {}", + method, path, decision.decision, decision.reason + ); if !decision.is_allowed() { if !user.is_authenticated() { + warn!( + "RBAC: Unauthorized access attempt to {} {} (no auth)", + method, path + ); return ( StatusCode::UNAUTHORIZED, Json(serde_json::json!({ @@ -656,6 +663,10 @@ pub async fn rbac_middleware_fn( .into_response(); } + warn!( + "RBAC: Forbidden access to {} {} for user {} with roles {:?}", + method, path, user.user_id, user.roles + ); return ( StatusCode::FORBIDDEN, Json(serde_json::json!({