diff --git a/src/handlers/http/users/dashboards.rs b/src/handlers/http/users/dashboards.rs index 38aad3fa9..be894da5b 100644 --- a/src/handlers/http/users/dashboards.rs +++ b/src/handlers/http/users/dashboards.rs @@ -23,7 +23,7 @@ use crate::{ metastore::MetastoreError, storage::ObjectStorageError, users::dashboards::{DASHBOARDS, Dashboard, Tile, validate_dashboard_id}, - utils::{get_hash, get_user_from_request}, + utils::{get_hash, get_user_from_request, is_admin}, }; use actix_web::{ HttpRequest, HttpResponse, Responder, @@ -104,8 +104,10 @@ pub async fn update_dashboard( ) -> Result { let user_id = get_hash(&get_user_from_request(&req)?); let dashboard_id = validate_dashboard_id(dashboard_id.into_inner())?; + let is_admin = is_admin(&req).map_err(|e| DashboardError::Custom(e.to_string()))?; + let mut existing_dashboard = DASHBOARDS - .get_dashboard_by_user(dashboard_id, &user_id) + .get_dashboard_by_user(dashboard_id, &user_id, is_admin) .await .ok_or(DashboardError::Metadata( "Dashboard does not exist or user is not authorized", @@ -189,9 +191,13 @@ pub async fn delete_dashboard( dashboard_id: Path, ) -> Result { let user_id = get_hash(&get_user_from_request(&req)?); + let is_admin = is_admin(&req).map_err(|e| DashboardError::Custom(e.to_string()))?; + let dashboard_id = validate_dashboard_id(dashboard_id.into_inner())?; - DASHBOARDS.delete_dashboard(&user_id, dashboard_id).await?; + DASHBOARDS + .delete_dashboard(&user_id, dashboard_id, is_admin) + .await?; Ok(HttpResponse::Ok().finish()) } @@ -207,9 +213,10 @@ pub async fn add_tile( let user_id = get_hash(&get_user_from_request(&req)?); let dashboard_id = validate_dashboard_id(dashboard_id.into_inner())?; + let is_admin = is_admin(&req).map_err(|e| DashboardError::Custom(e.to_string()))?; let mut dashboard = DASHBOARDS - .get_dashboard_by_user(dashboard_id, &user_id) + .get_dashboard_by_user(dashboard_id, &user_id, is_admin) .await .ok_or(DashboardError::Unauthorized)?; diff --git a/src/handlers/http/users/filters.rs b/src/handlers/http/users/filters.rs index 98559a910..629d1ded2 100644 --- a/src/handlers/http/users/filters.rs +++ b/src/handlers/http/users/filters.rs @@ -22,7 +22,7 @@ use crate::{ parseable::PARSEABLE, storage::ObjectStorageError, users::filters::{CURRENT_FILTER_VERSION, FILTERS, Filter}, - utils::{actix::extract_session_key_from_req, get_hash, get_user_from_request}, + utils::{actix::extract_session_key_from_req, get_hash, get_user_from_request, is_admin}, }; use actix_web::{ HttpRequest, HttpResponse, Responder, @@ -46,8 +46,11 @@ pub async fn get( ) -> Result { let user_id = get_user_from_request(&req)?; let filter_id = filter_id.into_inner(); - - if let Some(filter) = FILTERS.get_filter(&filter_id, &get_hash(&user_id)).await { + let is_admin = is_admin(&req).map_err(|e| FiltersError::Custom(e.to_string()))?; + if let Some(filter) = FILTERS + .get_filter(&filter_id, &get_hash(&user_id), is_admin) + .await + { return Ok((web::Json(filter), StatusCode::OK)); } @@ -81,7 +84,13 @@ pub async fn update( let mut user_id = get_user_from_request(&req)?; user_id = get_hash(&user_id); let filter_id = filter_id.into_inner(); - if FILTERS.get_filter(&filter_id, &user_id).await.is_none() { + let is_admin = is_admin(&req).map_err(|e| FiltersError::Custom(e.to_string()))?; + + if FILTERS + .get_filter(&filter_id, &user_id, is_admin) + .await + .is_none() + { return Err(FiltersError::Metadata( "Filter does not exist or user is not authorized", )); @@ -103,8 +112,9 @@ pub async fn delete( let mut user_id = get_user_from_request(&req)?; user_id = get_hash(&user_id); let filter_id = filter_id.into_inner(); + let is_admin = is_admin(&req).map_err(|e| FiltersError::Custom(e.to_string()))?; let filter = FILTERS - .get_filter(&filter_id, &user_id) + .get_filter(&filter_id, &user_id, is_admin) .await .ok_or(FiltersError::Metadata( "Filter does not exist or user is not authorized", diff --git a/src/users/dashboards.rs b/src/users/dashboards.rs index fbf83fda6..d2e21a05a 100644 --- a/src/users/dashboards.rs +++ b/src/users/dashboards.rs @@ -295,9 +295,10 @@ impl Dashboards { &self, user_id: &str, dashboard_id: Ulid, + is_admin: bool, ) -> Result<(), DashboardError> { let obj = self - .ensure_dashboard_ownership(dashboard_id, user_id) + .ensure_dashboard_ownership(dashboard_id, user_id, is_admin) .await?; { @@ -335,6 +336,7 @@ impl Dashboards { &self, dashboard_id: Ulid, user_id: &str, + is_admin: bool, ) -> Option { self.0 .read() @@ -344,7 +346,7 @@ impl Dashboards { d.dashboard_id .as_ref() .is_some_and(|id| *id == dashboard_id) - && d.author == Some(user_id.to_string()) + && (d.author == Some(user_id.to_string()) || is_admin) }) .cloned() } @@ -409,8 +411,9 @@ impl Dashboards { &self, dashboard_id: Ulid, user_id: &str, + is_admin: bool, ) -> Result { - self.get_dashboard_by_user(dashboard_id, user_id) + self.get_dashboard_by_user(dashboard_id, user_id, is_admin) .await .ok_or_else(|| { DashboardError::Metadata( diff --git a/src/users/filters.rs b/src/users/filters.rs index b8cabc34f..627ece52b 100644 --- a/src/users/filters.rs +++ b/src/users/filters.rs @@ -132,13 +132,19 @@ impl Filters { s.retain(|f| f.filter_id != Some(filter_id.to_string())); } - pub async fn get_filter(&self, filter_id: &str, user_id: &str) -> Option { + pub async fn get_filter( + &self, + filter_id: &str, + user_id: &str, + is_admin: bool, + ) -> Option { self.0 .read() .await .iter() .find(|f| { - f.filter_id == Some(filter_id.to_string()) && f.user_id == Some(user_id.to_string()) + f.filter_id == Some(filter_id.to_string()) + && (f.user_id == Some(user_id.to_string()) || is_admin) }) .cloned() } diff --git a/src/utils/mod.rs b/src/utils/mod.rs index fc3290ab4..b0a49d201 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -145,3 +145,22 @@ pub async fn user_auth_for_datasets( Ok(()) } + +pub fn is_admin(req: &HttpRequest) -> Result { + let session_key = + extract_session_key_from_req(req).map_err(|e| anyhow::Error::msg(e.to_string()))?; + + let permissions = Users.get_permissions(&session_key); + + // Check if user has admin permissions (Action::All on All resources) + for permission in permissions.iter() { + match permission { + Permission::Resource(Action::All, ParseableResourceType::All) => { + return Ok(true); + } + _ => continue, + } + } + + Ok(false) +}