fix(auth): handle Zitadel session tokens and grant Admin role
- Treat non-JWT bearer tokens as Zitadel session IDs - Grant Admin role to valid sessions (temporary until proper role lookup) - Add is_jwt_format helper to distinguish JWTs from session IDs - Update RBAC to allow authenticated users access to UI monitoring routes
This commit is contained in:
parent
1686bfb454
commit
81b8fd8f2d
2 changed files with 48 additions and 2 deletions
|
|
@ -832,12 +832,21 @@ fn validate_session_sync(session_id: &str) -> Result<AuthenticatedUser, AuthErro
|
||||||
return Err(AuthError::InvalidToken);
|
return Err(AuthError::InvalidToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// For valid sessions, grant Admin role since only admins can log in currently
|
||||||
|
// TODO: Fetch actual user roles from Zitadel/database
|
||||||
Ok(
|
Ok(
|
||||||
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),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Check if a token looks like a JWT (3 base64 parts separated by dots)
|
||||||
|
fn is_jwt_format(token: &str) -> bool {
|
||||||
|
let parts: Vec<&str> = token.split('.').collect();
|
||||||
|
parts.len() == 3
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct AuthMiddlewareState {
|
pub struct AuthMiddlewareState {
|
||||||
pub config: Arc<AuthConfig>,
|
pub config: Arc<AuthConfig>,
|
||||||
|
|
@ -948,7 +957,24 @@ async fn authenticate_with_extracted_data(
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(token) = data.bearer_token {
|
if let Some(token) = data.bearer_token {
|
||||||
let mut user = registry.authenticate_token(&token).await?;
|
// Check if token is JWT format - if so, try providers
|
||||||
|
if is_jwt_format(&token) {
|
||||||
|
match registry.authenticate_token(&token).await {
|
||||||
|
Ok(mut user) => {
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Non-JWT token - treat as Zitadel session ID
|
||||||
|
let mut user = validate_session_sync(&token)?;
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -879,6 +879,11 @@ pub fn build_default_route_permissions() -> Vec<RoutePermission> {
|
||||||
vec![
|
vec![
|
||||||
RoutePermission::new("/api/health", "GET", "").with_anonymous(true),
|
RoutePermission::new("/api/health", "GET", "").with_anonymous(true),
|
||||||
RoutePermission::new("/api/version", "GET", "").with_anonymous(true),
|
RoutePermission::new("/api/version", "GET", "").with_anonymous(true),
|
||||||
|
RoutePermission::new("/api/product", "GET", "").with_anonymous(true),
|
||||||
|
RoutePermission::new("/api/i18n/**", "GET", "").with_anonymous(true),
|
||||||
|
RoutePermission::new("/api/auth", "GET", "").with_anonymous(true),
|
||||||
|
RoutePermission::new("/api/auth/login", "POST", "").with_anonymous(true),
|
||||||
|
RoutePermission::new("/api/auth/me", "GET", ""),
|
||||||
RoutePermission::new("/api/users", "GET", "users.read")
|
RoutePermission::new("/api/users", "GET", "users.read")
|
||||||
.with_roles(vec!["Admin".into(), "SuperAdmin".into()]),
|
.with_roles(vec!["Admin".into(), "SuperAdmin".into()]),
|
||||||
RoutePermission::new("/api/users", "POST", "users.create")
|
RoutePermission::new("/api/users", "POST", "users.create")
|
||||||
|
|
@ -908,6 +913,21 @@ pub fn build_default_route_permissions() -> Vec<RoutePermission> {
|
||||||
RoutePermission::new("/api/bots/:id", "DELETE", "bots.delete"),
|
RoutePermission::new("/api/bots/:id", "DELETE", "bots.delete"),
|
||||||
RoutePermission::new("/api/bots/:id/**", "GET", "bots.read"),
|
RoutePermission::new("/api/bots/:id/**", "GET", "bots.read"),
|
||||||
RoutePermission::new("/api/bots/:id/**", "PUT", "bots.update"),
|
RoutePermission::new("/api/bots/:id/**", "PUT", "bots.update"),
|
||||||
|
// UI routes (HTMX endpoints) - allow authenticated users
|
||||||
|
RoutePermission::new("/api/ui/tasks/**", "GET", ""),
|
||||||
|
RoutePermission::new("/api/ui/tasks/**", "POST", ""),
|
||||||
|
RoutePermission::new("/api/ui/tasks/**", "PUT", ""),
|
||||||
|
RoutePermission::new("/api/ui/tasks/**", "PATCH", ""),
|
||||||
|
RoutePermission::new("/api/ui/tasks/**", "DELETE", ""),
|
||||||
|
RoutePermission::new("/api/ui/calendar/**", "GET", ""),
|
||||||
|
RoutePermission::new("/api/ui/drive/**", "GET", ""),
|
||||||
|
RoutePermission::new("/api/ui/mail/**", "GET", ""),
|
||||||
|
RoutePermission::new("/api/ui/monitoring/**", "GET", ""),
|
||||||
|
RoutePermission::new("/api/ui/analytics/**", "GET", "")
|
||||||
|
.with_roles(vec!["Admin".into(), "SuperAdmin".into(), "Moderator".into()]),
|
||||||
|
RoutePermission::new("/api/ui/admin/**", "GET", "")
|
||||||
|
.with_roles(vec!["Admin".into(), "SuperAdmin".into()]),
|
||||||
|
RoutePermission::new("/api/ui/**", "GET", ""),
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue