Skip to content

Commit

Permalink
[Workspace]Deny get or bulkGet for global data source (#8043) (#8051)
Browse files Browse the repository at this point in the history
* Deny get or bulkGet for global data source

* Changeset file for PR #8043 created/updated

---------

(cherry picked from commit d22b68b)

Signed-off-by: Lin Wang <wonglam@amazon.com>
Signed-off-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: opensearch-changeset-bot[bot] <154024398+opensearch-changeset-bot[bot]@users.noreply.github.com>
(cherry picked from commit 27cce8e)
Signed-off-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
  • Loading branch information
1 parent d7ce981 commit efb7058
Show file tree
Hide file tree
Showing 3 changed files with 83 additions and 1 deletion.
2 changes: 2 additions & 0 deletions changelogs/fragments/8043.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
feat:
- [Workspace]Deny get or bulkGet for global data source ([#8043](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/8043))
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,12 @@ const generateWorkspaceSavedObjectsClientWrapper = (role = NO_DASHBOARD_ADMIN) =
id: 'global-data-source',
attributes: { title: 'Global data source' },
},
{
type: DATA_SOURCE_SAVED_OBJECT_TYPE,
id: 'global-data-source-empty-workspaces',
attributes: { title: 'Global data source empty workspaces' },
workspaces: [],
},
{
type: DATA_SOURCE_SAVED_OBJECT_TYPE,
id: 'workspace-1-data-source',
Expand Down Expand Up @@ -620,6 +626,33 @@ describe('WorkspaceSavedObjectsClientWrapper', () => {
workspaces: ['workspace-1'],
});
});

it('should throw permission error when tried to access a global data source', async () => {
const { wrapper } = generateWorkspaceSavedObjectsClientWrapper();
let errorCatched;
try {
await wrapper.get('data-source', 'global-data-source');
} catch (e) {
errorCatched = e;
}
expect(errorCatched?.message).toEqual(
'Invalid data source permission, please associate it to current workspace'
);
});

it('should throw permission error when tried to access a empty workspaces global data source', async () => {
const { wrapper, requestMock } = generateWorkspaceSavedObjectsClientWrapper();
updateWorkspaceState(requestMock, { requestWorkspaceId: undefined });
let errorCatched;
try {
await wrapper.get('data-source', 'global-data-source-empty-workspaces');
} catch (e) {
errorCatched = e;
}
expect(errorCatched?.message).toEqual(
'Invalid data source permission, please associate it to current workspace'
);
});
});
describe('bulk get', () => {
it("should call permission validate with object's workspace and throw permission error", async () => {
Expand Down Expand Up @@ -744,6 +777,36 @@ describe('WorkspaceSavedObjectsClientWrapper', () => {
],
});
});

it('should throw permission error when tried to bulk get global data source', async () => {
const { wrapper, requestMock } = generateWorkspaceSavedObjectsClientWrapper();
updateWorkspaceState(requestMock, { requestWorkspaceId: undefined });
let errorCatched;
try {
await wrapper.bulkGet([{ type: 'data-source', id: 'global-data-source' }]);
} catch (e) {
errorCatched = e;
}
expect(errorCatched?.message).toEqual(
'Invalid data source permission, please associate it to current workspace'
);
});

it('should throw permission error when tried to bulk get a empty workspace global data source', async () => {
const { wrapper, requestMock } = generateWorkspaceSavedObjectsClientWrapper();
updateWorkspaceState(requestMock, { requestWorkspaceId: undefined });
let errorCatched;
try {
await wrapper.bulkGet([
{ type: 'data-source', id: 'global-data-source-empty-workspaces' },
]);
} catch (e) {
errorCatched = e;
}
expect(errorCatched?.message).toEqual(
'Invalid data source permission, please associate it to current workspace'
);
});
});
describe('find', () => {
it('should call client.find with consistent params when ACLSearchParams and workspaceOperator not provided', async () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,24 @@ export class WorkspaceSavedObjectsClientWrapper {
request: OpenSearchDashboardsRequest
) => {
const requestWorkspaceId = getWorkspaceState(request).requestWorkspaceId;
return !requestWorkspaceId || !!object.workspaces?.includes(requestWorkspaceId);
// Deny access if the object is a global data source (no workspaces assigned)
if (!object.workspaces || object.workspaces.length === 0) {
return false;
}
/**
* Allow access if no specific workspace is requested.
* This typically occurs when retrieving data sources or performing operations
* that don't require a specific workspace, such as pages within the
* Data Administration navigation group that include a data source picker.
*/
if (!requestWorkspaceId) {
return true;
}
/*
* Allow access if the requested workspace matches one of the object's assigned workspaces
* This ensures that the user can only access data sources within their current workspace
*/
return object.workspaces.includes(requestWorkspaceId);
};

private getWorkspaceTypeEnabledClient(request: OpenSearchDashboardsRequest) {
Expand Down

0 comments on commit efb7058

Please sign in to comment.