From bb3d90be61e024faa985eafa3ab923bea1407dcf Mon Sep 17 00:00:00 2001 From: SuZhou-Joe Date: Mon, 11 Mar 2024 15:04:48 +0800 Subject: [PATCH] Revert "refactor: remove dashboard admin implementation (#159)" This reverts commit 47e10e4d81ca193028297868beb9eaaced1c00dc. --- config/opensearch_dashboards.yml | 4 +++ src/plugins/workspace/config.ts | 12 +++++++ .../workspace_saved_objects_client_wrapper.ts | 35 ++++++++++++++++++- 3 files changed, 50 insertions(+), 1 deletion(-) diff --git a/config/opensearch_dashboards.yml b/config/opensearch_dashboards.yml index 6e8ded0d1e62..824b3f599327 100644 --- a/config/opensearch_dashboards.yml +++ b/config/opensearch_dashboards.yml @@ -283,3 +283,7 @@ # Set the value to true to enable workspace feature # workspace.enabled: false + +# Set the backend roles, whoever has the backend roles defined in this config will be regard as dashboard admin. +# Dashboard admin will have the access to all the workspaces and objects inside OpenSearch Dashboards. +# workspace.dashboardAdmin.backendRoles: ["dashboard_admin"] \ No newline at end of file diff --git a/src/plugins/workspace/config.ts b/src/plugins/workspace/config.ts index 9c40a690fdb7..422ef024ba86 100644 --- a/src/plugins/workspace/config.ts +++ b/src/plugins/workspace/config.ts @@ -10,6 +10,18 @@ export const configSchema = schema.object({ permission: schema.object({ enabled: schema.boolean({ defaultValue: true }), }), + dashboardAdmin: schema.object( + { + backendRoles: schema.arrayOf(schema.string(), { + defaultValue: ['dashboard_admin'], + }), + }, + { + defaultValue: { + backendRoles: ['dashboard_admin'], + }, + } + ), }); export type ConfigSchema = TypeOf; diff --git a/src/plugins/workspace/server/saved_objects/workspace_saved_objects_client_wrapper.ts b/src/plugins/workspace/server/saved_objects/workspace_saved_objects_client_wrapper.ts index 41a4c7ee7407..89384dec9b71 100644 --- a/src/plugins/workspace/server/saved_objects/workspace_saved_objects_client_wrapper.ts +++ b/src/plugins/workspace/server/saved_objects/workspace_saved_objects_client_wrapper.ts @@ -5,6 +5,8 @@ import { i18n } from '@osd/i18n'; import { intersection } from 'lodash'; +import { Observable } from 'rxjs'; +import { first } from 'rxjs/operators'; import { OpenSearchDashboardsRequest, @@ -34,6 +36,7 @@ import { import { SavedObjectsPermissionControlContract } from '../permission_control/client'; import { getPrincipalsFromRequest } from '../utils'; import { WORKSPACE_SAVED_OBJECTS_CLIENT_WRAPPER_ID } from '../../common/constants'; +import { ConfigSchema } from '../../config'; // Can't throw unauthorized for now, the page will be refreshed if unauthorized const generateWorkspacePermissionError = () => @@ -56,6 +59,7 @@ const generateSavedObjectsPermissionError = () => export class WorkspaceSavedObjectsClientWrapper { private getScopedClient?: SavedObjectsServiceStart['getScopedClient']; + private config?: ConfigSchema; private formatWorkspacePermissionModeToStringArray( permission: WorkspacePermissionMode | WorkspacePermissionMode[] ): string[] { @@ -128,6 +132,14 @@ export class WorkspaceSavedObjectsClientWrapper { return false; }; + private isDashboardAdmin(request: OpenSearchDashboardsRequest): boolean { + const config = this.config || ({} as ConfigSchema); + const principals = getPrincipalsFromRequest(request); + const adminBackendRoles = config?.dashboardAdmin?.backendRoles || []; + const matchAny = principals?.groups?.some((item) => adminBackendRoles.includes(item)) || false; + return matchAny; + } + /** * check if the type include workspace * Workspace permission check is totally different from object permission check. @@ -528,6 +540,12 @@ export class WorkspaceSavedObjectsClientWrapper { return await wrapperOptions.client.deleteByWorkspace(workspace, options); }; + const isDashboardAdmin = this.isDashboardAdmin(wrapperOptions.request); + + if (isDashboardAdmin) { + return wrapperOptions.client; + } + return { ...wrapperOptions.client, get: getWithWorkspacePermissionControl, @@ -547,5 +565,20 @@ export class WorkspaceSavedObjectsClientWrapper { }; }; - constructor(private readonly permissionControl: SavedObjectsPermissionControlContract) {} + constructor( + private readonly permissionControl: SavedObjectsPermissionControlContract, + private readonly options: { + config$: Observable; + } + ) { + this.options.config$.subscribe((config) => { + this.config = config; + }); + this.options.config$ + .pipe(first()) + .toPromise() + .then((config) => { + this.config = config; + }); + } }