Skip to content

Commit 8a066f9

Browse files
[Workspace] Add ACL related test cases (opensearch-project#1644) (opensearch-project#1652)
* feat: add acl related test cases Signed-off-by: SuZhou-Joe <suzhou@amazon.com> * feat: update Signed-off-by: SuZhou-Joe <suzhou@amazon.com> * feat: remove useless resources Signed-off-by: SuZhou-Joe <suzhou@amazon.com> * feat: update Signed-off-by: SuZhou-Joe <suzhou@amazon.com> * feat: use admin user to clean up all the resources Signed-off-by: SuZhou-Joe <suzhou@amazon.com> --------- Signed-off-by: SuZhou-Joe <suzhou@amazon.com> (cherry picked from commit 3047f25) Co-authored-by: SuZhou-Joe <suzhou@amazon.com>
1 parent 068bda7 commit 8a066f9

File tree

1 file changed

+232
-0
lines changed

1 file changed

+232
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,232 @@
1+
/*
2+
* Copyright OpenSearch Contributors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
import { BASE_PATH } from '../../../../utils/base_constants';
7+
import { ADMIN_AUTH } from '../../../../utils/commands';
8+
import workspaceTestUser from '../../../../fixtures/dashboard/opensearch_dashboards/workspace/workspaceTestUser.json';
9+
import workspaceTestRole from '../../../../fixtures/dashboard/opensearch_dashboards/workspace/workspaceTestRole.json';
10+
import { WORKSPACE_API_PREFIX } from '../../../../utils/dashboards/workspace-plugin/constants';
11+
12+
let noPermissionWorkspaceName = 'acl_no_permission_workspace';
13+
let readOnlyWorkspaceName = 'acl_readonly_workspace';
14+
let libraryWriteWorkspaceName = 'acl_library_write_workspace';
15+
let ownerWorkspaceName = 'acl_owner_workspace';
16+
17+
let noPermissionWorkspaceId = '';
18+
let readOnlyWorkspaceId = '';
19+
let libraryWriteWorkspaceId = '';
20+
let ownerWorkspaceId = '';
21+
let datasourceId = '';
22+
23+
const getPolicy = (permission, userName) => ({
24+
[permission]: {
25+
users: [userName],
26+
},
27+
});
28+
29+
const NON_DASHBOARDS_ADMIN_USERNAME = 'workspace-acl-test';
30+
const WORKSPACE_TEST_ROLE_NAME = 'workspace-acl-test-role';
31+
32+
const ACLPolicyMap = {
33+
[noPermissionWorkspaceName]: {},
34+
[readOnlyWorkspaceName]: {
35+
...getPolicy('read', NON_DASHBOARDS_ADMIN_USERNAME),
36+
...getPolicy('library_read', NON_DASHBOARDS_ADMIN_USERNAME),
37+
},
38+
[libraryWriteWorkspaceName]: {
39+
...getPolicy('read', NON_DASHBOARDS_ADMIN_USERNAME),
40+
...getPolicy('library_write', NON_DASHBOARDS_ADMIN_USERNAME),
41+
},
42+
[ownerWorkspaceName]: {
43+
...getPolicy('write', NON_DASHBOARDS_ADMIN_USERNAME),
44+
...getPolicy('library_write', NON_DASHBOARDS_ADMIN_USERNAME),
45+
},
46+
};
47+
48+
const setupWorkspace = (workspaceName, datasourceId) => {
49+
return cy
50+
.createWorkspace({
51+
name: workspaceName,
52+
settings: {
53+
...(datasourceId ? { dataSources: [datasourceId] } : {}),
54+
permissions: ACLPolicyMap[workspaceName],
55+
},
56+
})
57+
.then((value) => {
58+
// load sample data
59+
cy.loadSampleDataForWorkspace('ecommerce', value, datasourceId);
60+
cy.wrap(value);
61+
});
62+
};
63+
64+
const setupAllTheWorkspaces = () => {
65+
setupWorkspace(noPermissionWorkspaceName, datasourceId).then(
66+
(value) => (noPermissionWorkspaceId = value)
67+
);
68+
setupWorkspace(readOnlyWorkspaceName, datasourceId).then(
69+
(value) => (readOnlyWorkspaceId = value)
70+
);
71+
setupWorkspace(libraryWriteWorkspaceName, datasourceId).then(
72+
(value) => (libraryWriteWorkspaceId = value)
73+
);
74+
setupWorkspace(ownerWorkspaceName, datasourceId).then(
75+
(value) => (ownerWorkspaceId = value)
76+
);
77+
};
78+
79+
if (
80+
Cypress.env('WORKSPACE_ENABLED') &&
81+
Cypress.env('SAVED_OBJECTS_PERMISSION_ENABLED') &&
82+
Cypress.env('SECURITY_ENABLED')
83+
) {
84+
describe('Workspace ACL', () => {
85+
const originalUser = ADMIN_AUTH.username;
86+
const originalPassword = ADMIN_AUTH.password;
87+
before(() => {
88+
cy.deleteWorkspaceByName(noPermissionWorkspaceName);
89+
cy.deleteWorkspaceByName(readOnlyWorkspaceName);
90+
cy.deleteWorkspaceByName(libraryWriteWorkspaceName);
91+
cy.deleteWorkspaceByName(ownerWorkspaceName);
92+
93+
cy.createInternalUser(NON_DASHBOARDS_ADMIN_USERNAME, workspaceTestUser);
94+
cy.createRole(WORKSPACE_TEST_ROLE_NAME, workspaceTestRole);
95+
cy.createRoleMapping(WORKSPACE_TEST_ROLE_NAME, {
96+
users: [NON_DASHBOARDS_ADMIN_USERNAME],
97+
});
98+
99+
if (Cypress.env('DATASOURCE_MANAGEMENT_ENABLED')) {
100+
cy.createDataSourceNoAuth().then((result) => {
101+
datasourceId = result[0];
102+
expect(datasourceId).to.be.a('string').that.is.not.empty;
103+
setupAllTheWorkspaces(datasourceId);
104+
});
105+
} else {
106+
setupAllTheWorkspaces(datasourceId);
107+
}
108+
});
109+
110+
after(() => {
111+
ADMIN_AUTH.newUser = originalUser;
112+
ADMIN_AUTH.newPassword = originalPassword;
113+
cy.removeSampleDataForWorkspace(
114+
'ecommerce',
115+
ownerWorkspaceId,
116+
datasourceId
117+
);
118+
cy.deleteWorkspaceByName(noPermissionWorkspaceName);
119+
cy.deleteWorkspaceByName(readOnlyWorkspaceName);
120+
cy.deleteWorkspaceByName(libraryWriteWorkspaceName);
121+
cy.deleteWorkspaceByName(ownerWorkspaceName);
122+
if (Cypress.env('DATASOURCE_MANAGEMENT_ENABLED')) {
123+
cy.deleteDataSource(datasourceId);
124+
}
125+
readOnlyWorkspaceId = '';
126+
libraryWriteWorkspaceId = '';
127+
128+
cy.deleteRoleMapping(WORKSPACE_TEST_ROLE_NAME);
129+
cy.deleteInternalUser(NON_DASHBOARDS_ADMIN_USERNAME);
130+
cy.deleteRole(WORKSPACE_TEST_ROLE_NAME);
131+
});
132+
133+
describe('Normal user', () => {
134+
beforeEach(() => {
135+
ADMIN_AUTH.newUser = NON_DASHBOARDS_ADMIN_USERNAME;
136+
ADMIN_AUTH.newPassword = workspaceTestUser.password;
137+
});
138+
139+
it('Normal user should not be able to create workspace', () => {
140+
cy.request({
141+
method: 'POST',
142+
url: `${BASE_PATH}${WORKSPACE_API_PREFIX}`,
143+
headers: {
144+
'osd-xsrf': true,
145+
},
146+
body: {
147+
attributes: {
148+
name: 'test_workspace',
149+
features: ['use-case-observability'],
150+
description: 'test_description',
151+
},
152+
},
153+
failOnStatusCode: false,
154+
}).then((resp) =>
155+
cy
156+
.wrap(resp.body.error)
157+
.should('equal', 'Invalid permission, please contact OSD admin')
158+
);
159+
});
160+
161+
it('Normal users should only see the workspaces they have permission with', () => {
162+
cy.visit(`${BASE_PATH}/app/home`);
163+
cy.contains(readOnlyWorkspaceName);
164+
cy.contains(noPermissionWorkspaceName).should('not.exist');
165+
});
166+
167+
it('Readonly users should not be allowed to update dashboards/visualizations within the workspace', () => {
168+
cy.visit(`${BASE_PATH}/w/${readOnlyWorkspaceId}/app/visualize`);
169+
cy.contains(/\[eCommerce\] Markdown/).click();
170+
cy.getElementByTestId('visualizeSaveButton').click();
171+
cy.getElementByTestId('confirmSaveSavedObjectButton').click();
172+
cy.contains('Forbidden');
173+
});
174+
175+
it('Normal users should not be allowed to visit workspace he/she has no permission', () => {
176+
cy.visit(`${BASE_PATH}/w/${noPermissionWorkspaceId}/app/objects`);
177+
cy.contains('Invalid saved objects permission');
178+
});
179+
180+
it('Normal users should only see the workspaces he has library_write permission in the target workspaces list of duplicate modal', () => {
181+
cy.visit(`${BASE_PATH}/w/${readOnlyWorkspaceId}/app/objects`);
182+
cy.getElementByTestId('savedObjectsTableRowTitle').should('exist');
183+
cy.getElementByTestId('duplicateObjects')
184+
.click()
185+
.getElementByTestId('savedObjectsDuplicateModal')
186+
.find('[data-test-subj="comboBoxInput"]')
187+
.click();
188+
189+
cy.contains(libraryWriteWorkspaceName);
190+
cy.contains(ownerWorkspaceName);
191+
cy.contains(noPermissionWorkspaceName).should('not.exist');
192+
});
193+
194+
it('Users should not be able to update default index pattern / default data source if he/she is not the workspace owner', () => {
195+
cy.visit(`${BASE_PATH}/w/${libraryWriteWorkspaceId}/app/indexPatterns`);
196+
cy.contains('opensearch_dashboards_sample_data_ecommerce').click();
197+
cy.getElementByTestId('setDefaultIndexPatternButton').click();
198+
cy.contains('Unable to update UI setting');
199+
});
200+
201+
it('Normal users should not be able to find objects from other workspaces when inside a workspace', () => {
202+
cy.visit(`${BASE_PATH}/w/${readOnlyWorkspaceId}/app/objects`);
203+
cy.getElementByTestId('savedObjectsTableRowTitle').should('exist');
204+
cy.getElementByTestId(
205+
'savedObjectsTableColumn-workspace_column'
206+
).should('not.exist');
207+
cy.contains('opensearch_dashboards_sample_data_ecommerce');
208+
// Electron old version may not support search event, so we manually trigger a search event
209+
cy.getElementByTestId('savedObjectSearchBar')
210+
.type('opensearch_dashboards_sample_data_ecommerce{enter}')
211+
.trigger('search');
212+
cy.getElementByTestId('savedObjectsTableRowTitle').should(
213+
'have.length',
214+
1
215+
);
216+
});
217+
218+
if (Cypress.env('DATASOURCE_MANAGEMENT_ENABLED')) {
219+
it('Normal users should not be able to associate / dissociate data sources from workspace.', () => {
220+
cy.visit(`${BASE_PATH}/w/${ownerWorkspaceId}/app/dataSources`);
221+
cy.contains('Data sources');
222+
cy.getElementByTestId('workspaceAssociateDataSourceButton').should(
223+
'not.exist'
224+
);
225+
cy.getElementByTestId(
226+
'dataSourcesManagement-dataSourceTable-dissociateButton'
227+
).should('not.exist');
228+
});
229+
}
230+
});
231+
});
232+
}

0 commit comments

Comments
 (0)