Skip to content

Commit

Permalink
[Workspace][Feature] Add ACL related functions (#5084) (#6405)
Browse files Browse the repository at this point in the history
* [Workspace] Add ACL related functions for workspace (#146)

* consume permissions in repository
* feat: consume permissions in serializer
* Add unit tests for consuming permissions in repository
* Remove double exclamation
* Rename some variables
* Remove duplicated semicolon
* Add permissions field to the mapping only if the permission control is enabled
* Fix test failure
* Add feature flag config to the yml file
* Make the comment of feature flag more clear
* Make comment more clear
* Remove management permission type
* Fix test failure

---------

(cherry picked from commit 54c36fe)

Signed-off-by: gaobinlong <[email protected]>
Signed-off-by: SuZhou-Joe <[email protected]>
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: Josh Romero <[email protected]>
Co-authored-by: SuZhou-Joe <[email protected]>
  • Loading branch information
4 people authored Apr 12, 2024
1 parent 31f6376 commit 8666f1e
Show file tree
Hide file tree
Showing 16 changed files with 1,049 additions and 28 deletions.
5 changes: 5 additions & 0 deletions config/opensearch_dashboards.yml
Original file line number Diff line number Diff line change
Expand Up @@ -306,5 +306,10 @@
# Set the value of this setting to true to enable plugin augmentation
# vis_augmenter.pluginAugmentationEnabled: true

# Set the value to true to enable permission control for saved objects
# Permission control depends on OpenSearch Dashboards has authentication enabled, set it to false when the security plugin is not installed,
# if the security plugin is not installed and this config is true, permission control takes no effect.
# savedObjects.permission.enabled: true

# Set the value to true to enable workspace feature
# workspace.enabled: false
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,12 @@ describe('buildActiveMappings', () => {
expect(hashes.aaa).not.toEqual(hashes.ccc);
});

test('permissions field is added when permission control flag is enabled', () => {
const rawConfig = configMock.create();
rawConfig.get.mockReturnValue(true);
expect(buildActiveMappings({}, rawConfig)).toHaveProperty('properties.permissions');
});

test('workspaces field is added when workspace feature flag is enabled', () => {
const rawConfig = configMock.create();
rawConfig.get.mockReturnValue(true);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import { cloneDeep, mapValues } from 'lodash';
import { Config } from '@osd/config';
import {
IndexMapping,
SavedObjectsFieldMapping,
SavedObjectsMappingProperties,
SavedObjectsTypeMappingDefinitions,
} from './../../mappings';
Expand All @@ -55,6 +56,29 @@ export function buildActiveMappings(

let mergedProperties = validateAndMerge(mapping.properties, typeDefinitions);
// if permission control for saved objects is enabled, the permissions field should be added to the mapping
if (opensearchDashboardsRawConfig?.get('savedObjects.permission.enabled')) {
const principals: SavedObjectsFieldMapping = {
properties: {
users: {
type: 'keyword',
},
groups: {
type: 'keyword',
},
},
};
mergedProperties = validateAndMerge(mapping.properties, {
permissions: {
properties: {
read: principals,
write: principals,
library_read: principals,
library_write: principals,
},
},
});
}

if (opensearchDashboardsRawConfig?.get('workspace.enabled')) {
mergedProperties = validateAndMerge(mapping.properties, {
workspaces: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,12 +60,105 @@ describe('IndexMigrator', () => {
};
});

test('creates the index when permission control for saved objects is enabled', async () => {
const { client } = testOpts;

testOpts.mappingProperties = { foo: { type: 'long' } as any };
const rawConfig = configMock.create();
rawConfig.get.mockImplementation((path) => {
if (path === 'savedObjects.permission.enabled') {
return true;
} else {
return false;
}
});
testOpts.opensearchDashboardsRawConfig = rawConfig;

withIndex(client, { index: { statusCode: 404 }, alias: { statusCode: 404 } });

await new IndexMigrator(testOpts).migrate();

expect(client.indices.create).toHaveBeenCalledWith({
body: {
mappings: {
dynamic: 'strict',
_meta: {
migrationMappingPropertyHashes: {
foo: '18c78c995965207ed3f6e7fc5c6e55fe',
migrationVersion: '4a1746014a75ade3a714e1db5763276f',
namespace: '2f4316de49999235636386fe51dc06c1',
namespaces: '2f4316de49999235636386fe51dc06c1',
originId: '2f4316de49999235636386fe51dc06c1',
permissions: 'f3ad308fa2a0c34007eb9ad461d6294a',
references: '7997cf5a56cc02bdc9c93361bde732b0',
type: '2f4316de49999235636386fe51dc06c1',
updated_at: '00da57df13e94e9d98437d13ace4bfe0',
},
},
properties: {
foo: { type: 'long' },
migrationVersion: { dynamic: 'true', type: 'object' },
namespace: { type: 'keyword' },
namespaces: { type: 'keyword' },
originId: { type: 'keyword' },
type: { type: 'keyword' },
updated_at: { type: 'date' },
permissions: {
properties: {
library_read: {
properties: {
users: { type: 'keyword' },
groups: { type: 'keyword' },
},
},
library_write: {
properties: {
users: { type: 'keyword' },
groups: { type: 'keyword' },
},
},
read: {
properties: {
users: { type: 'keyword' },
groups: { type: 'keyword' },
},
},
write: {
properties: {
users: { type: 'keyword' },
groups: { type: 'keyword' },
},
},
},
},
references: {
type: 'nested',
properties: {
name: { type: 'keyword' },
type: { type: 'keyword' },
id: { type: 'keyword' },
},
},
},
},
settings: { number_of_shards: 1, auto_expand_replicas: '0-1' },
},
index: '.kibana_1',
});
});

test('creates the index when workspaces feature flag is enabled', async () => {
const { client } = testOpts;

testOpts.mappingProperties = { foo: { type: 'long' } as any };
const rawConfig = configMock.create();
rawConfig.get.mockReturnValue(true);
rawConfig.get.mockImplementation((path) => {
if (path === 'workspace.enabled') {
return true;
} else {
return false;
}
});
testOpts.opensearchDashboardsRawConfig = rawConfig;

withIndex(client, { index: { statusCode: 404 }, alias: { statusCode: 404 } });
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,14 @@ describe('OpenSearchDashboardsMigrator', () => {
expect(mappings).toMatchSnapshot();
});

it('permissions field exists in the mappings when the feature is enabled', () => {
const options = mockOptions(false, true);
const mappings = new OpenSearchDashboardsMigrator(options).getActiveMappings();
expect(mappings).toHaveProperty('properties.permissions');
});

it('workspaces field exists in the mappings when the feature is enabled', () => {
const options = mockOptions(true);
const options = mockOptions(true, false);
const mappings = new OpenSearchDashboardsMigrator(options).getActiveMappings();
expect(mappings).toHaveProperty('properties.workspaces');
});
Expand Down Expand Up @@ -153,12 +159,29 @@ type MockedOptions = OpenSearchDashboardsMigratorOptions & {
client: ReturnType<typeof opensearchClientMock.createOpenSearchClient>;
};

const mockOptions = (isWorkspaceEnabled?: boolean) => {
const mockOptions = (isWorkspaceEnabled?: boolean, isPermissionControlEnabled?: boolean) => {
const rawConfig = configMock.create();
rawConfig.get.mockReturnValue(false);
if (isWorkspaceEnabled) {
if (isWorkspaceEnabled || isPermissionControlEnabled) {
rawConfig.get.mockReturnValue(true);
}
rawConfig.get.mockImplementation((path) => {
if (path === 'savedObjects.permission.enabled') {
if (isPermissionControlEnabled) {
return true;
} else {
return false;
}
} else if (path === 'workspace.enabled') {
if (isWorkspaceEnabled) {
return true;
} else {
return false;
}
} else {
return false;
}
});
const options: MockedOptions = {
logger: loggingSystemMock.create().get(),
opensearchDashboardsVersion: '8.2.3',
Expand Down
Loading

0 comments on commit 8666f1e

Please sign in to comment.