mirror of https://github.com/buster-so/buster.git
get max permissions between direct and workspace
This commit is contained in:
parent
a0a1e11493
commit
955aab3232
|
@ -92,6 +92,8 @@ pub enum TeamToUserRole {
|
|||
Hash,
|
||||
diesel::AsExpression,
|
||||
diesel::FromSqlRow,
|
||||
Ord,
|
||||
PartialOrd,
|
||||
)]
|
||||
#[diesel(sql_type = sql_types::AssetPermissionRoleEnum)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
|
|
|
@ -12,7 +12,7 @@ use database::{
|
|||
use diesel::{ExpressionMethods, JoinOnDsl, NullableExpressionMethods, QueryDsl, Queryable};
|
||||
use diesel_async::RunQueryDsl;
|
||||
use middleware::AuthenticatedUser;
|
||||
use sharing::check_permission_access;
|
||||
use sharing::{check_permission_access, compute_effective_permission};
|
||||
use tracing;
|
||||
use uuid::Uuid;
|
||||
|
||||
|
@ -96,22 +96,22 @@ pub async fn get_collection_handler(
|
|||
return Err(anyhow!("You don't have permission to view this collection"));
|
||||
}
|
||||
|
||||
// Extract permission for consistent use in response
|
||||
// If the asset is public and the user has no direct permission, default to CanView
|
||||
let mut permission = collection_with_permission.permission
|
||||
.unwrap_or(AssetPermissionRole::CanView);
|
||||
// Compute the effective permission (highest of direct and workspace sharing)
|
||||
let permission = compute_effective_permission(
|
||||
collection_with_permission.permission,
|
||||
collection_with_permission.collection.workspace_sharing,
|
||||
collection_with_permission.collection.organization_id,
|
||||
&user.organizations,
|
||||
).unwrap_or(AssetPermissionRole::CanView);
|
||||
|
||||
// Check if user is WorkspaceAdmin or DataAdmin for this organization
|
||||
let is_admin = user.organizations.iter().any(|org| {
|
||||
org.id == collection_with_permission.collection.organization_id
|
||||
&& (org.role == database::enums::UserOrganizationRole::WorkspaceAdmin
|
||||
|| org.role == database::enums::UserOrganizationRole::DataAdmin)
|
||||
});
|
||||
|
||||
if is_admin {
|
||||
// Admin users get Owner permissions
|
||||
permission = AssetPermissionRole::Owner;
|
||||
}
|
||||
tracing::debug!(
|
||||
collection_id = %req.id,
|
||||
user_id = %user.id,
|
||||
direct_permission = ?collection_with_permission.permission,
|
||||
workspace_sharing = ?collection_with_permission.collection.workspace_sharing,
|
||||
effective_permission = ?permission,
|
||||
"Computed effective permission for collection"
|
||||
);
|
||||
|
||||
let mut conn = match get_pg_pool().get().await {
|
||||
Ok(conn) => conn,
|
||||
|
|
|
@ -21,7 +21,7 @@ use database::schema::{
|
|||
asset_permissions, collections, collections_to_assets, dashboard_files, metric_files, users,
|
||||
};
|
||||
use database::types::{MetricYml, VersionHistory};
|
||||
use sharing::check_permission_access;
|
||||
use sharing::{check_permission_access, compute_effective_permission};
|
||||
|
||||
use super::{
|
||||
BusterDashboard, BusterDashboardResponse, DashboardConfig, DashboardRow, DashboardRowItem,
|
||||
|
@ -131,22 +131,23 @@ pub async fn get_dashboard_handler(
|
|||
tracing::debug!(dashboard_id = %dashboard_id, ?direct_permission_level, has_sufficient_direct_permission, "Direct permission check result");
|
||||
|
||||
if has_sufficient_direct_permission {
|
||||
// Check if user is WorkspaceAdmin or DataAdmin for this organization
|
||||
let is_admin = user.organizations.iter().any(|org| {
|
||||
org.id == dashboard_file.organization_id
|
||||
&& (org.role == database::enums::UserOrganizationRole::WorkspaceAdmin
|
||||
|| org.role == database::enums::UserOrganizationRole::DataAdmin)
|
||||
});
|
||||
// Compute the effective permission (highest of direct and workspace sharing)
|
||||
let effective_permission = compute_effective_permission(
|
||||
direct_permission_level,
|
||||
dashboard_file.workspace_sharing,
|
||||
dashboard_file.organization_id,
|
||||
&user.organizations,
|
||||
);
|
||||
|
||||
if is_admin {
|
||||
// Admin users get Owner permissions
|
||||
permission = AssetPermissionRole::Owner;
|
||||
tracing::debug!(dashboard_id = %dashboard_id, user_id = %user.id, ?permission, "Granting Owner access to admin user.");
|
||||
} else {
|
||||
// User has direct permission, use that role
|
||||
permission = direct_permission_level.unwrap_or(AssetPermissionRole::CanView); // Default just in case
|
||||
tracing::debug!(dashboard_id = %dashboard_id, user_id = %user.id, ?permission, "Granting access via direct permission.");
|
||||
}
|
||||
permission = effective_permission.unwrap_or(AssetPermissionRole::CanView);
|
||||
tracing::debug!(
|
||||
dashboard_id = %dashboard_id,
|
||||
user_id = %user.id,
|
||||
?direct_permission_level,
|
||||
workspace_sharing = ?dashboard_file.workspace_sharing,
|
||||
?permission,
|
||||
"Granting access with effective permission (max of direct and workspace sharing)."
|
||||
);
|
||||
} else {
|
||||
// No sufficient direct/admin permission, check if user has access via a chat
|
||||
tracing::debug!(dashboard_id = %dashboard_id, "Insufficient direct/admin permission. Checking chat access.");
|
||||
|
|
|
@ -17,7 +17,7 @@ use database::schema::{
|
|||
asset_permissions, collections, collections_to_assets, dashboard_files, datasets, metric_files,
|
||||
metric_files_to_dashboard_files, metric_files_to_datasets, users,
|
||||
};
|
||||
use sharing::check_permission_access;
|
||||
use sharing::{check_permission_access, compute_effective_permission};
|
||||
|
||||
use super::Version;
|
||||
|
||||
|
@ -142,22 +142,23 @@ pub async fn get_metric_for_dashboard_handler(
|
|||
tracing::debug!(metric_id = %metric_id, ?direct_permission_level, has_sufficient_direct_permission, "Direct permission check result");
|
||||
|
||||
if has_sufficient_direct_permission {
|
||||
// Check if user is WorkspaceAdmin or DataAdmin for this organization
|
||||
let is_admin = user.organizations.iter().any(|org| {
|
||||
org.id == metric_file.organization_id
|
||||
&& (org.role == database::enums::UserOrganizationRole::WorkspaceAdmin
|
||||
|| org.role == database::enums::UserOrganizationRole::DataAdmin)
|
||||
});
|
||||
// Compute the effective permission (highest of direct and workspace sharing)
|
||||
let effective_permission = compute_effective_permission(
|
||||
direct_permission_level,
|
||||
metric_file.workspace_sharing,
|
||||
metric_file.organization_id,
|
||||
&user.organizations,
|
||||
);
|
||||
|
||||
if is_admin {
|
||||
// Admin users get Owner permissions
|
||||
permission = AssetPermissionRole::Owner;
|
||||
tracing::debug!(metric_id = %metric_id, user_id = %user.id, ?permission, "Granting Owner access to admin user.");
|
||||
} else {
|
||||
// User has direct permission, use that role
|
||||
permission = direct_permission_level.unwrap_or(AssetPermissionRole::CanView); // Default just in case
|
||||
tracing::debug!(metric_id = %metric_id, user_id = %user.id, ?permission, "Granting access via direct permission.");
|
||||
}
|
||||
permission = effective_permission.unwrap_or(AssetPermissionRole::CanView);
|
||||
tracing::debug!(
|
||||
metric_id = %metric_id,
|
||||
user_id = %user.id,
|
||||
?direct_permission_level,
|
||||
workspace_sharing = ?metric_file.workspace_sharing,
|
||||
?permission,
|
||||
"Granting access with effective permission (max of direct and workspace sharing)."
|
||||
);
|
||||
} else {
|
||||
// No sufficient direct/admin permission, check if user has access via a dashboard
|
||||
tracing::debug!(metric_id = %metric_id, "Insufficient direct/admin permission. Checking dashboard access.");
|
||||
|
|
|
@ -15,7 +15,7 @@ use database::schema::{
|
|||
asset_permissions, collections, collections_to_assets, dashboard_files, datasets,
|
||||
metric_files_to_dashboard_files, users, metric_files_to_datasets,
|
||||
};
|
||||
use sharing::check_permission_access;
|
||||
use sharing::{check_permission_access, compute_effective_permission};
|
||||
|
||||
use super::Version;
|
||||
|
||||
|
@ -140,22 +140,23 @@ pub async fn get_metric_handler(
|
|||
tracing::debug!(metric_id = %metric_id, ?direct_permission_level, has_sufficient_direct_permission, "Direct permission check result");
|
||||
|
||||
if has_sufficient_direct_permission {
|
||||
// Check if user is WorkspaceAdmin or DataAdmin for this organization
|
||||
let is_admin = user.organizations.iter().any(|org| {
|
||||
org.id == metric_file.organization_id
|
||||
&& (org.role == database::enums::UserOrganizationRole::WorkspaceAdmin
|
||||
|| org.role == database::enums::UserOrganizationRole::DataAdmin)
|
||||
});
|
||||
// Compute the effective permission (highest of direct and workspace sharing)
|
||||
let effective_permission = compute_effective_permission(
|
||||
direct_permission_level,
|
||||
metric_file.workspace_sharing,
|
||||
metric_file.organization_id,
|
||||
&user.organizations,
|
||||
);
|
||||
|
||||
if is_admin {
|
||||
// Admin users get Owner permissions
|
||||
permission = AssetPermissionRole::Owner;
|
||||
tracing::debug!(metric_id = %metric_id, user_id = %user.id, ?permission, "Granting Owner access to admin user.");
|
||||
} else {
|
||||
// User has direct permission, use that role
|
||||
permission = direct_permission_level.unwrap_or(AssetPermissionRole::CanView); // Default just in case
|
||||
tracing::debug!(metric_id = %metric_id, user_id = %user.id, ?permission, "Granting access via direct permission.");
|
||||
}
|
||||
permission = effective_permission.unwrap_or(AssetPermissionRole::CanView);
|
||||
tracing::debug!(
|
||||
metric_id = %metric_id,
|
||||
user_id = %user.id,
|
||||
?direct_permission_level,
|
||||
workspace_sharing = ?metric_file.workspace_sharing,
|
||||
?permission,
|
||||
"Granting access with effective permission (max of direct and workspace sharing)."
|
||||
);
|
||||
} else {
|
||||
// No sufficient direct/admin permission, check if user has access via a dashboard
|
||||
tracing::debug!(metric_id = %metric_id, "Insufficient direct/admin permission. Checking dashboard access.");
|
||||
|
|
|
@ -5,6 +5,63 @@ use diesel::{BoolExpressionMethods, ExpressionMethods, JoinOnDsl, QueryDsl, Opti
|
|||
use diesel_async::RunQueryDsl;
|
||||
use middleware::OrganizationMembership;
|
||||
use uuid::Uuid;
|
||||
use std::cmp::Ordering;
|
||||
|
||||
/// Computes the effective permission level for a user on an asset by taking the maximum
|
||||
/// of their direct permission and workspace sharing permission.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `direct_permission` - The user's direct permission on the asset (if any)
|
||||
/// * `workspace_sharing` - The workspace sharing level for the asset
|
||||
/// * `organization_id` - UUID of the organization
|
||||
/// * `organization_role_grants` - User's organization memberships
|
||||
///
|
||||
/// # Returns
|
||||
/// * `Option<AssetPermissionRole>` - The highest permission level available to the user
|
||||
pub fn compute_effective_permission(
|
||||
direct_permission: Option<AssetPermissionRole>,
|
||||
workspace_sharing: WorkspaceSharing,
|
||||
organization_id: Uuid,
|
||||
organization_role_grants: &[OrganizationMembership],
|
||||
) -> Option<AssetPermissionRole> {
|
||||
// First check if the user has WorkspaceAdmin or DataAdmin role for the organization
|
||||
for org in organization_role_grants {
|
||||
if org.id == organization_id
|
||||
&& (org.role == UserOrganizationRole::WorkspaceAdmin
|
||||
|| org.role == UserOrganizationRole::DataAdmin)
|
||||
{
|
||||
return Some(AssetPermissionRole::Owner);
|
||||
}
|
||||
}
|
||||
|
||||
// Compute workspace-granted permission
|
||||
let workspace_permission = if workspace_sharing != WorkspaceSharing::None {
|
||||
// Check if user is member of the organization
|
||||
if organization_role_grants.iter().any(|org| org.id == organization_id) {
|
||||
match workspace_sharing {
|
||||
WorkspaceSharing::CanView => Some(AssetPermissionRole::CanView),
|
||||
WorkspaceSharing::CanEdit => Some(AssetPermissionRole::CanEdit),
|
||||
WorkspaceSharing::FullAccess => Some(AssetPermissionRole::FullAccess),
|
||||
WorkspaceSharing::None => None,
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
// Return the highest permission level
|
||||
match (direct_permission, workspace_permission) {
|
||||
(Some(direct), Some(workspace)) => {
|
||||
// Use the max method to get the higher permission
|
||||
Some(direct.max(workspace))
|
||||
}
|
||||
(Some(direct), None) => Some(direct),
|
||||
(None, Some(workspace)) => Some(workspace),
|
||||
(None, None) => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks if a user has sufficient permissions based on organization roles and asset permissions.
|
||||
///
|
||||
|
|
|
@ -19,4 +19,8 @@ pub use types::{
|
|||
SerializableAssetPermission, UserInfo,
|
||||
};
|
||||
pub use user_lookup::find_user_by_email;
|
||||
pub use asset_access_checks::{check_permission_access, check_metric_dashboard_access, check_metric_chat_access, check_dashboard_chat_access};
|
||||
pub use asset_access_checks::{
|
||||
check_permission_access, check_metric_dashboard_access, check_metric_chat_access,
|
||||
check_dashboard_chat_access, check_metric_collection_access, check_dashboard_collection_access,
|
||||
compute_effective_permission
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue