From 7bac3603dfea7e06abb2ce4df7500555150860ab Mon Sep 17 00:00:00 2001 From: SuZhou-Joe Date: Fri, 25 Aug 2023 14:51:54 +0800 Subject: [PATCH] feat: change savedObjectsClient in runtime Signed-off-by: SuZhou-Joe --- src/plugins/workspace/server/plugin.ts | 13 ++-- .../workspace_saved_objects_client_wrapper.ts | 60 +++++++++++++------ 2 files changed, 50 insertions(+), 23 deletions(-) diff --git a/src/plugins/workspace/server/plugin.ts b/src/plugins/workspace/server/plugin.ts index c389b3df3ed1..5d6fe4ad6987 100644 --- a/src/plugins/workspace/server/plugin.ts +++ b/src/plugins/workspace/server/plugin.ts @@ -34,6 +34,7 @@ export class WorkspacePlugin implements Plugin<{}, {}> { private coreStart?: CoreStart; private config$: Observable; private enabled$: BehaviorSubject = new BehaviorSubject(false); + private workspaceSavedObjectsClientWrapper?: WorkspaceSavedObjectsClientWrapper; private get isEnabled() { return this.enabled$.getValue(); @@ -70,7 +71,7 @@ export class WorkspacePlugin implements Plugin<{}, {}> { this.client = new WorkspaceClientWithSavedObject(core); await this.client.setup(core); - const workspaceSavedObjectsClientWrapper = new WorkspaceSavedObjectsClientWrapper( + this.workspaceSavedObjectsClientWrapper = new WorkspaceSavedObjectsClientWrapper( core.savedObjects.permissionControl, { config$: this.config$, @@ -81,7 +82,7 @@ export class WorkspacePlugin implements Plugin<{}, {}> { core.savedObjects.addClientWrapper( 0, 'workspace', - workspaceSavedObjectsClientWrapper.wrapperFactory + this.workspaceSavedObjectsClientWrapper.wrapperFactory ); this.proxyWorkspaceTrafficToRealHandler(core); @@ -94,10 +95,6 @@ export class WorkspacePlugin implements Plugin<{}, {}> { config$: this.config$, }); - core.savedObjects.setClientFactoryProvider((repositoryFactory) => () => - new SavedObjectsClient(repositoryFactory.createInternalRepository()) - ); - return { client: this.client, enabled$: this.enabled$, @@ -202,6 +199,10 @@ export class WorkspacePlugin implements Plugin<{}, {}> { this.coreStart = core; + this.workspaceSavedObjectsClientWrapper?.setInternalRepositoryFactory( + core.savedObjects.createInternalRepository + ); + this.setupWorkspaceFeatureFlag(); this.enabled$.subscribe((enabled) => { 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 901b5e9ed94c..d88ec4d63039 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 @@ -30,6 +30,8 @@ import { WORKSPACE_TYPE, ACL, WorkspacePermissionMode, + SavedObjectsClient, + SavedObjectsRepositoryFactory, } from '../../../../core/server'; import { ConfigSchema } from '../../config'; @@ -60,6 +62,7 @@ const isWorkspacesLikeAttributes = (attributes: unknown): attributes is Attribut export class WorkspaceSavedObjectsClientWrapper { private config?: ConfigSchema; + private internalRepositoryFactory?: SavedObjectsRepositoryFactory['createInternalRepository']; private formatWorkspacePermissionModeToStringArray( permission: WorkspacePermissionMode | WorkspacePermissionMode[] ): string[] { @@ -160,6 +163,23 @@ export class WorkspaceSavedObjectsClientWrapper { } public wrapperFactory: SavedObjectsClientWrapperFactory = (wrapperOptions) => { + /** + * The client here is scopedSavedObjectsClient by default + */ + let client = wrapperOptions.client; + const featureFlagEnabled = this.options.enabled$.getValue(); + + if (!featureFlagEnabled) { + return client; + } + + /** + * If featureFlag is open and we have internalRepositoryFactory + * Use internal repository as access control will be provided by ACL. + */ + if (featureFlagEnabled && this.internalRepositoryFactory) { + client = new SavedObjectsClient(this.internalRepositoryFactory()); + } const deleteWithWorkspacePermissionControl = async ( type: string, id: string, @@ -171,13 +191,13 @@ export class WorkspaceSavedObjectsClientWrapper { ]); } - const objectToDeleted = await wrapperOptions.client.get(type, id, options); + const objectToDeleted = await client.get(type, id, options); await this.validateMultiWorkspacesPermissions( objectToDeleted.workspaces, wrapperOptions.request, [WorkspacePermissionMode.LibraryWrite, WorkspacePermissionMode.Management] ); - return await wrapperOptions.client.delete(type, id, options); + return await client.delete(type, id, options); }; const updateWithWorkspacePermissionControl = async ( @@ -191,7 +211,7 @@ export class WorkspaceSavedObjectsClientWrapper { WorkspacePermissionMode.Management, ]); } - return await wrapperOptions.client.update(type, id, attributes, options); + return await client.update(type, id, attributes, options); }; const bulkUpdateWithWorkspacePermissionControl = async ( @@ -213,7 +233,7 @@ export class WorkspaceSavedObjectsClientWrapper { throw generateWorkspacePermissionError(); } - return await wrapperOptions.client.bulkUpdate(objects, options); + return await client.bulkUpdate(objects, options); }; const bulkCreateWithWorkspacePermissionControl = async ( @@ -226,7 +246,7 @@ export class WorkspaceSavedObjectsClientWrapper { WorkspacePermissionMode.Management, ]); } - return await wrapperOptions.client.bulkCreate(objects, options); + return await client.bulkCreate(objects, options); }; const createWithWorkspacePermissionControl = async ( @@ -241,7 +261,7 @@ export class WorkspaceSavedObjectsClientWrapper { [WorkspacePermissionMode.LibraryWrite, WorkspacePermissionMode.Management] ); } - return await wrapperOptions.client.create(type, attributes, options); + return await client.create(type, attributes, options); }; const getWithWorkspacePermissionControl = async ( @@ -249,7 +269,7 @@ export class WorkspaceSavedObjectsClientWrapper { id: string, options: SavedObjectsBaseOptions = {} ): Promise> => { - const objectToGet = await wrapperOptions.client.get(type, id, options); + const objectToGet = await client.get(type, id, options); await this.validateAtLeastOnePermittedWorkspaces( objectToGet.workspaces, wrapperOptions.request, @@ -266,7 +286,7 @@ export class WorkspaceSavedObjectsClientWrapper { objects: SavedObjectsBulkGetObject[] = [], options: SavedObjectsBaseOptions = {} ): Promise> => { - const objectToBulkGet = await wrapperOptions.client.bulkGet(objects, options); + const objectToBulkGet = await client.bulkGet(objects, options); for (const object of objectToBulkGet.saved_objects) { await this.validateAtLeastOnePermittedWorkspaces( object.workspaces, @@ -375,7 +395,7 @@ export class WorkspaceSavedObjectsClientWrapper { } } - return await wrapperOptions.client.find(options); + return await client.find(options); }; const addToWorkspacesWithPermissionControl = async ( @@ -402,24 +422,24 @@ export class WorkspaceSavedObjectsClientWrapper { throw generateSavedObjectsPermissionError(); } - return await wrapperOptions.client.addToWorkspaces(objects, targetWorkspaces, options); + return await client.addToWorkspaces(objects, targetWorkspaces, options); }; const isDashboardAdmin = this.isDashboardAdmin(wrapperOptions.request); - if (isDashboardAdmin || !this.options.enabled$.getValue()) { - return wrapperOptions.client; + if (isDashboardAdmin) { + return client; } return { - ...wrapperOptions.client, + ...client, get: getWithWorkspacePermissionControl, - checkConflicts: wrapperOptions.client.checkConflicts, + checkConflicts: client.checkConflicts, find: findWithWorkspacePermissionControl, bulkGet: bulkGetWithWorkspacePermissionControl, - errors: wrapperOptions.client.errors, - addToNamespaces: wrapperOptions.client.addToNamespaces, - deleteFromNamespaces: wrapperOptions.client.deleteFromNamespaces, + errors: client.errors, + addToNamespaces: client.addToNamespaces, + deleteFromNamespaces: client.deleteFromNamespaces, create: createWithWorkspacePermissionControl, bulkCreate: bulkCreateWithWorkspacePermissionControl, delete: deleteWithWorkspacePermissionControl, @@ -429,6 +449,12 @@ export class WorkspaceSavedObjectsClientWrapper { }; }; + public setInternalRepositoryFactory( + internalRepositoryFactory: SavedObjectsRepositoryFactory['createInternalRepository'] + ) { + this.internalRepositoryFactory = internalRepositoryFactory; + } + constructor( private readonly permissionControl: SavedObjectsPermissionControlContract, private readonly options: {