Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

dashboard admin(groups/users) implementation and integrating with dynamic application config #303

Merged

Conversation

yubonluo
Copy link

@yubonluo yubonluo commented Mar 20, 2024

This reverts commit 47e10e4.

Description

dashboard admin(groups/users) implementation and integrating with dynamic application config

Issues Resolved

Screenshot

Testing the changes

This function can only be used when the workspace and security plugin are open.
If you want to turn on dynamic application configuration, you must change opensearch_dashboards.yml:

application_config.enabled: true

Below is the CURL command to view all configurations.

curl --insecure {osd endpoint}/api/appconfig -u 'admin:admin' -X GET

Below is the CURL command to view the configuration of an entity.

curl --insecure {osd endpoint}/api/appconfig/opensearchDashboards.dashboardAdmin.groups -u 'admin:admin' -X GET
curl --insecure {osd endpoint}/api/appconfig/opensearchDashboards.dashboardAdmin.users -u 'admin:admin' -X GET

Below is the CURL command to update the configuration of an entity.

curl --insecure {osd endpoint}/api/appconfig/opensearchDashboards.dashboardAdmin.users -X POST -H 'Accept: application/json' -H 'Content-Type: application/json' -H 'osd-xsrf: osd-fetch' -H 'Sec-Fetch-Dest: empty' --data-raw '{"newValue":"[\"dashboard_admin\"]"}' -u 'admin:admin'

Below is the CURL command to delete the configuration of an entity.

curl --insecure {osd endpoint}/api/appconfig/opensearchDashboards.dashboardAdmin.users -X DELETE -H 'osd-xsrf: osd-fetch' -H 'Sec-Fetch-Dest: empty' -u 'admin:admin'

Check List

  • All tests pass
    • yarn test:jest
    • yarn test:jest_integration
  • New functionality includes testing.
  • New functionality has been documented.
  • Update CHANGELOG.md
  • Commits are signed per the DCO using --signoff

@codecov-commenter
Copy link

codecov-commenter commented Mar 20, 2024

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 55.93%. Comparing base (0f34d69) to head (acfb166).
Report is 13 commits behind head on workspace-pr-integr.

Additional details and impacted files
@@                   Coverage Diff                    @@
##           workspace-pr-integr     #303       +/-   ##
========================================================
+ Coverage                35.17%   55.93%   +20.76%     
========================================================
  Files                     1885     2254      +369     
  Lines                    36421    42172     +5751     
  Branches                  6672     7487      +815     
========================================================
+ Hits                     12810    23590    +10780     
+ Misses                   22761    17225     -5536     
- Partials                   850     1357      +507     
Flag Coverage Δ
_2 55.35% <100.00%> (?)
_4 35.16% <0.00%> (-0.01%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

const adminGroups = config?.dashboardAdmin?.groups || [];
const adminUsers = config?.dashboardAdmin?.users || [];
const groupMatchAny = groups?.some((group) => adminGroups.includes(group)) || false;
const userMatchAny = users?.some((user) => adminUsers.includes(user)) || false;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shall we remove ? after users and groups?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will delete invalid ?

# Set the backend roles in groups or users, whoever has the backend roles or exactly match the user ids 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.groups: ["dashboard_admin"]
# workspace.dashboardAdmin.users: ["dashboard_admin"]
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The naming workspace.dashboardAdmin may confuse me, it sounds like the admin for dashboard type only. I come few names like workspace.dashboardsAdmin,
workspace.admin or workpsace.superAdmin

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

workspace.admin may be confusing as admin of workspace stands for the the users who have write permission on specific workspaces, vote for superAdmin.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If there is no configuration named workspace.admin, would workspace.superAdmin also be confused?

@@ -140,6 +144,24 @@ export class WorkspaceSavedObjectsClientWrapper {
return false;
};

private isDashboardAdmin(request: OpenSearchDashboardsRequest): boolean {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Prefer renaming to isRequestByDashboardAdmin.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

@yubonluo yubonluo changed the title dashboard admin(groups/users) implementation and add unit/integration… dashboard admin(groups/users) implementation and integrating with dynamic application config Apr 2, 2024
Signed-off-by: yubonluo <yubonluo@amazon.com>
Signed-off-by: yubonluo <yubonluo@amazon.com>
@@ -83,8 +88,35 @@ export class WorkspacePlugin implements Plugin<{}, {}> {
if (isPermissionControlEnabled) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shall we move the permission control logic to a separate method like setupPermission? It seems over 30 lines.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, I have moved the related logic to a separate setupPermission method.

@@ -66,8 +70,32 @@ const getDefaultValuesForEmpty = <T>(values: T[] | undefined, defaultValues: T[]
return !values || values.length === 0 ? defaultValues : values;
};

export const isRequestByDashboardAdmin = (
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Prefer move to some utils file

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have moved to src/plugins/workspace/server/utils.ts and add unit test.

@@ -51,6 +51,8 @@ const repositoryKit = (() => {

const permittedRequest = httpServerMock.createOpenSearchDashboardsRequest();
const notPermittedRequest = httpServerMock.createOpenSearchDashboardsRequest();
const groupIsDashboardAdminRequest = httpServerMock.createOpenSearchDashboardsRequest();
const UserIdIsDashboardAdminRequest = httpServerMock.createOpenSearchDashboardsRequest();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Prefer renaming to userIdIsDashboardAdminRequest

Copy link
Author

@yubonluo yubonluo Apr 3, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is no relevant logic of users/groups in the wrapper, so I uniformly use the dashboardAdminRequest name in the test file.

@@ -59,6 +61,8 @@ describe('WorkspaceSavedObjectsClientWrapper', () => {
let osd: TestOpenSearchDashboardsUtils;
let permittedSavedObjectedClient: SavedObjectsClientContract;
let notPermittedSavedObjectedClient: SavedObjectsClientContract;
let groupIsDashboardAdminSavedObjectedClient: SavedObjectsClientContract;
let UserIdIsdashboardAdminSavedObjectedClient: SavedObjectsClientContract;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Prefer userIdIsdashboardAdminSavedObjectedClient

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is no relevant logic of users/groups in the wrapper, so I uniformly use the dashboardAdminSavedObjectedClient name in the test file.

request,
adminGroups ? [adminGroups] : [],
adminUsers ? [adminUsers] : [],
this.permissionControl!
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we use assert here, permissionControl is inited above and its type is fixed.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are right, the relevant logic has been deleted.

Signed-off-by: yubonluo <yubonluo@amazon.com>
Signed-off-by: yubonluo <yubonluo@amazon.com>
Signed-off-by: yubonluo <yubonluo@amazon.com>
Comment on lines 65 to 66
groups: string[],
users: string[],
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: I'd recommend combine these two params into a param named principals: Principals.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think using deconstructed code is more conducive to subsequent use.

@@ -55,12 +60,98 @@ export class WorkspacePlugin implements Plugin<{}, {}> {
});
}

private isRequestByDashboardAdmin(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can be a util function inside another file.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have moved to src/plugins/workspace/server/utils.ts and add unit test.


private async setupPermission(
core: CoreSetup,
config: WorkspacePluginConfigType,
Copy link
Collaborator

@SuZhou-Joe SuZhou-Joe Apr 3, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we leverage the existing property config$?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

} catch (e) {
return toolkit.next();
}
if (groups.length === 0 && users.length === 0) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the cluster does not require authentication, anyone can be dashboardAdmin I think.
@ruanyl @wanglam @raintygao what do you think?

Copy link
Collaborator

@raintygao raintygao Apr 3, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense, a bit like OSD without security plugin installed that will have almost admin permissions. Also want to hear other's thoughts.

Copy link
Author

@yubonluo yubonluo Apr 3, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You mean to update isDashboardAdmin state to true if groups.length === 0 && users.length === 0 when both the security plugin and savedObject.permission.enabled are open.

Comment on lines 78 to 80
updateWorkspaceState(request, {
isDashboardAdmin: groupMatchAny || userMatchAny,
});
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From the function name, I do not think it appropriate to update anything inside this function.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, I will change the function name to updateDashboardAdminStateForRequest

yubonluo and others added 7 commits April 3, 2024 13:14
Signed-off-by: yubonluo <yubonluo@amazon.com>
Signed-off-by: yubonluo <yubonluo@amazon.com>
Signed-off-by: yubonluo <yubonluo@amazon.com>
Signed-off-by: yubonluo <yubonluo@amazon.com>
Signed-off-by: yubonluo <yubonluo@amazon.com>
Signed-off-by: yubonluo <yubonluo@amazon.com>
Signed-off-by: yubonluo <yubonluo@amazon.com>
Signed-off-by: yubonluo <yubonluo@amazon.com>
Signed-off-by: yubonluo <yubonluo@amazon.com>
@yubonluo
Copy link
Author

yubonluo commented Apr 9, 2024

@ruanyl If you have any concerns, Please help me view this PR.

this.workspaceSavedObjectsClientWrapper.wrapperFactory
);
}
if (isPermissionControlEnabled) await this.setupPermission(core, { applicationConfig });
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems the await is not needed here.

@@ -64,12 +70,80 @@ export class WorkspacePlugin implements Plugin<WorkspacePluginSetup, WorkspacePl
});
}

private async setupPermission(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need to declare as a async function here I think

Comment on lines 90 to 92
updateWorkspaceState(request, {
isDashboardAdmin: false,
});
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why don't we use updateDashboardAdminStateForRequest method here?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If users/groups is null, we can prevent the program from running down in advance. Meanwhile, configGroups/configUsers has not been obtained.

Comment on lines 115 to 116
configGroups ? [configGroups] : [],
configUsers ? [configUsers] : []
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
configGroups ? [configGroups] : [],
configUsers ? [configUsers] : []
configGroups ? configGroups : [],
configUsers ? configUsers : []

configGroups and configUsers should already be array I think?

Signed-off-by: yubonluo <yubonluo@amazon.com>
Signed-off-by: yubonluo <yubonluo@amazon.com>
Signed-off-by: yubonluo <yubonluo@amazon.com>
Signed-off-by: yubonluo <yubonluo@amazon.com>
import { getWorkspaceState } from '../../../core/server/utils';
import { AppPluginSetupDependencies } from './types';
import { Observable, of } from 'rxjs';
import { error } from 'console';
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's this used for?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will use throw new Error('') to replace it.

Signed-off-by: yubonluo <yubonluo@amazon.com>
@SuZhou-Joe SuZhou-Joe merged commit dffd70b into ruanyl:workspace-pr-integr Apr 12, 2024
45 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants