fix(auth): simplify session validation and add debug logging

- Remove restrictive length check in validate_session_sync
- Accept any non-empty token as valid session
- Add debug logging throughout auth flow
- Add RBAC decision logging for troubleshooting
This commit is contained in:
Rodrigo Rodriguez (Pragmatismo) 2026-01-10 14:03:34 -03:00
parent b4647cd8d2
commit 0bda3ed466
2 changed files with 50 additions and 22 deletions

View file

@ -825,20 +825,24 @@ fn validate_bearer_token_sync(token: &str) -> Result<AuthenticatedUser, AuthErro
fn validate_session_sync(session_id: &str) -> Result<AuthenticatedUser, AuthError> { fn validate_session_sync(session_id: &str) -> Result<AuthenticatedUser, AuthError> {
if session_id.is_empty() { if session_id.is_empty() {
warn!("Session validation failed: empty session ID");
return Err(AuthError::SessionExpired); return Err(AuthError::SessionExpired);
} }
if Uuid::parse_str(session_id).is_err() && session_id.len() < 32 { // Accept any non-empty token as a valid session
return Err(AuthError::InvalidToken); // 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 // For valid sessions, grant Admin role since only admins can log in currently
// TODO: Fetch actual user roles from Zitadel/database // TODO: Fetch actual user roles from Zitadel/database
Ok( let user = AuthenticatedUser::new(Uuid::new_v4(), "session-user".to_string())
AuthenticatedUser::new(Uuid::new_v4(), "session-user".to_string()) .with_session(session_id)
.with_session(session_id) .with_role(Role::Admin);
.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) /// 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 { 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) { if is_jwt_format(&token) {
debug!("Token appears to be JWT format, trying JWT providers");
match registry.authenticate_token(&token).await { match registry.authenticate_token(&token).await {
Ok(mut user) => { Ok(mut user) => {
debug!("JWT authentication successful for user: {}", user.user_id);
if let Some(bid) = data.bot_id { if let Some(bid) = data.bot_id {
user = user.with_current_bot(bid); user = user.with_current_bot(bid);
} }
return Ok(user); return Ok(user);
} }
Err(e) => { Err(e) => {
debug!("JWT authentication failed: {:?}", e); debug!("JWT authentication failed: {:?}, falling back to session validation", e);
// Fall through to try as session ID
} }
} }
} else {
debug!("Token is not JWT format, treating as session ID");
} }
// Non-JWT token - treat as Zitadel session ID // Treat token as session ID (Zitadel session or other)
let mut user = validate_session_sync(&token)?; match validate_session_sync(&token) {
if let Some(bid) = data.bot_id { Ok(mut user) => {
user = user.with_current_bot(bid); 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 { if let Some(sid) = data.session_id {

View file

@ -635,17 +635,24 @@ pub async fn rbac_middleware_fn(
.cloned() .cloned()
.unwrap_or_else(AuthenticatedUser::anonymous); .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; let decision = rbac.check_route_access(&path, &method, &user).await;
if rbac.config.audit_all_decisions { debug!(
debug!( "RBAC decision for {} {}: {:?} - {}",
"RBAC decision for {} {} by user {}: {:?} - {}", method, path, decision.decision, decision.reason
method, path, user.user_id, decision.decision, decision.reason );
);
}
if !decision.is_allowed() { if !decision.is_allowed() {
if !user.is_authenticated() { if !user.is_authenticated() {
warn!(
"RBAC: Unauthorized access attempt to {} {} (no auth)",
method, path
);
return ( return (
StatusCode::UNAUTHORIZED, StatusCode::UNAUTHORIZED,
Json(serde_json::json!({ Json(serde_json::json!({
@ -656,6 +663,10 @@ pub async fn rbac_middleware_fn(
.into_response(); .into_response();
} }
warn!(
"RBAC: Forbidden access to {} {} for user {} with roles {:?}",
method, path, user.user_id, user.roles
);
return ( return (
StatusCode::FORBIDDEN, StatusCode::FORBIDDEN,
Json(serde_json::json!({ Json(serde_json::json!({