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

Adds Service Accounts tab #1502

Merged
merged 49 commits into from
Nov 17, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
1696500
Skip flaky SAML test as it awaits a fix (#1453)
cwperks May 31, 2023
9afe457
#2704 Adding Service Accounts page and link on side bar
samuelcostae Jul 3, 2023
d1bd4f5
#2704 Renaming 'internal users' to 'internal accounts' on dashboards …
samuelcostae Jul 6, 2023
b5253bf
Removing Prerequisite Checks Workflow (#1456)
RyanL1997 Jun 1, 2023
a3f2a4b
Removing Prerequisite Checks Workflow (#1456)
RyanL1997 Jun 1, 2023
9755c5b
Removing Prerequisite Checks Workflow (#1456)
RyanL1997 Jun 1, 2023
c384d6b
Use version from package.json for integration tests (#1463)
cwperks Jun 1, 2023
0a626c6
Adds 2.8 release notes (#1464)
DarshitChanpura Jun 1, 2023
3fdb80f
Switch to new tenant after loading a copied long URL (#1450)
leanneeliatra Jun 19, 2023
8f2b855
update permissions according to backend (#1480)
derek-ho Jun 22, 2023
2fd8881
Add the tenant into the short URL once the short URL is resolved (#1462)
leanneeliatra Jun 22, 2023
605b37b
Move security plugin from Plugin to Management section on left naviga…
Hailong-am Jun 29, 2023
70779e6
Increment version to 3.0.0.0 (#1496)
opensearch-trigger-bot[bot] Jun 30, 2023
fb2bab0
Fix a bad import path (#1498)
peternied Jun 30, 2023
0bb077e
filter high level groups and action groups by cluster and index (#1482)
derek-ho Jul 11, 2023
261a4c4
Use password message from /dashboardsinfo (#1503)
cwperks Jul 11, 2023
a40f8f0
Add release notes for 2.9.0.0 (#1510)
cwperks Jul 12, 2023
5034f93
Add eslint rule to forbid imports from path containing packages/ from…
cwperks Jul 19, 2023
0a65206
Force resolution of selenium-webdriver to 4.10.0 (#1541)
cwperks Aug 3, 2023
b188209
Change the version parsing command's regex to handle the case of doub…
RyanL1997 Aug 3, 2023
695fbd5
Add release notes for 1.3.12.0 (#1543)
cwperks Aug 4, 2023
772a81f
Modifying to use query params instead of new endpoints
samuelcostae Aug 10, 2023
a3be5ef
yarn lint fixes
samuelcostae Aug 10, 2023
9b18c00
Merge branch 'opensearch-project:main' into #2704
samuelcostae Aug 11, 2023
9cc9180
Merge branch 'opensearch-project:main' into #2704
samuelcostae Aug 11, 2023
3eccd84
Merge remote-tracking branch 'origin/#2704' into #2704
samuelcostae Aug 14, 2023
fc1b16f
Merge branch 'main' into #2704
samuelcostae Aug 18, 2023
f8f82f8
service-account-list.test.tsx added. Minor change resource name change
samuelcostae Aug 18, 2023
952c883
reverting accidental change to developer guide
samuelcostae Aug 18, 2023
bbcdf29
hardcoded collor CI error
samuelcostae Aug 19, 2023
0fc9773
Merge branch 'main' into #2704
DarshitChanpura Aug 23, 2023
9ca03f6
Merge branch 'main' into #2704
DarshitChanpura Sep 1, 2023
d8de3d5
Update public/apps/configuration/panels/service-account-list.tsx
stephen-crawford Sep 1, 2023
47fdcda
Merge branch 'main' into #2704
samuelcostae Sep 5, 2023
0bb96da
Merge remote-tracking branch 'origin/#2704' into #2704
samuelcostae Sep 7, 2023
10551f7
Service account description
samuelcostae Sep 7, 2023
bc100c0
Merge branch 'opensearch-project:main' into #2704
samuelcostae Sep 12, 2023
0570d1d
Merge branch 'main' into #2704
DarshitChanpura Oct 10, 2023
3d77166
Merge branch 'main' into #2704
samuelcostae Oct 12, 2023
6e3c85b
space removal
samuelcostae Oct 13, 2023
5330176
Merge branch 'main' into #2704
DarshitChanpura Oct 20, 2023
b676ca8
Merge branch 'main' into #2704
samuelcostae Oct 23, 2023
8c59065
Merge branch 'main' into #2704
DarshitChanpura Oct 31, 2023
273f9d8
Merge branch 'main' into #2704
samuelcostae Nov 3, 2023
388328d
"Internal User"
samuelcostae Nov 7, 2023
cf231bd
Lint
samuelcostae Nov 9, 2023
cba02fe
Merge branch 'main' into #2704
samuelcostae Nov 14, 2023
f541b0c
Merge branch 'main' into #2704
DarshitChanpura Nov 14, 2023
81442e8
Merge branch 'main' into #2704
DarshitChanpura Nov 14, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 2 additions & 10 deletions DEVELOPER_GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,17 +92,9 @@ Next, go to the base directory (`cd ../..`) and run `yarn osd bootstrap` to inst

From the base directory, run `yarn start`. This should start dashboard UI successfully. `Cmd+click` the url in the console output (It should look something like `http://0:5601/omf`). Once the page loads, you should be able to log in with user `admin` and password `admin`.

## Testing
## Integration Tests

The security-dashboards-plugin project uses Jest, Cypress and Selenium and makes use of the [OpenSearch Dashboards Functional Test]( https://github.com/opensearch-project/opensearch-dashboards-functional-test) project.

Make sure you have the OpenSearch and OpenSearch Dashboards running with the Security Plugin and that you can log in to it using a web browser.

Clone [OpenSearch Dashboards Functional Test]( https://github.com/opensearch-project/opensearch-dashboards-functional-test) in your local machine and follow the instructions in its DEVELOPER_GUIDE.md

### Integration Tests

To run selenium based integration tests, download and export the firefox web-driver to your PATH. Also, run `node scripts/build_opensearch_dashboards_platform_plugins.js` or `yarn start` before running the tests. This is essential to generate the bundles.
To run selenium based integration tests, download and export the firefox web-driver to your PATH. Also, run `node scripts/build_opensearch_dashboards_platform_plugins.js` or `yarn start` before running the tests. This is essential to generate the bundles.

The integration tests take advantage of [npm "pre" scripts](https://docs.npmjs.com/cli/v9/using-npm/scripts) to run a node based SAML IdP for integration tests related to SAML authentication. This will run a background process that listens on port 7000.

Expand Down
13 changes: 13 additions & 0 deletions public/apps/configuration/app-router.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
import { RoleView } from './panels/role-view/role-view';
import { TenantList } from './panels/tenant-list/tenant-list';
import { UserList } from './panels/user-list';
import { ServiceAccountList } from './panels/service-account-list';
import { Action, ResourceType, RouteItem, SubAction } from './types';
import { buildHashUrl, buildUrl } from './utils/url-builder';
import { CrossPageToast } from './cross-page-toast';
Expand All @@ -54,6 +55,10 @@
name: 'Internal users',
href: buildUrl(ResourceType.users),
},
[ResourceType.serviceAccounts]: {
name: 'Service Accounts',
href: buildUrl(ResourceType.serviceAccounts),
},
[ResourceType.permissions]: {
name: 'Permissions',
href: buildUrl(ResourceType.permissions),
Expand Down Expand Up @@ -85,6 +90,7 @@
ROUTE_MAP[ResourceType.auth],
ROUTE_MAP[ResourceType.roles],
ROUTE_MAP[ResourceType.users],
ROUTE_MAP[ResourceType.serviceAccounts],
ROUTE_MAP[ResourceType.permissions],
ROUTE_MAP[ResourceType.tenants],
ROUTE_MAP[ResourceType.auditLogging],
Expand Down Expand Up @@ -209,6 +215,13 @@
return <UserList {...props} />;
}}
/>
<Route
path={ROUTE_MAP.serviceAccounts.href}
render={() => {
setGlobalBreadcrumbs(ResourceType.serviceAccounts);
return <ServiceAccountList {...props} />;

Check warning on line 222 in public/apps/configuration/app-router.tsx

View check run for this annotation

Codecov / codecov/patch

public/apps/configuration/app-router.tsx#L220-L222

Added lines #L220 - L222 were not covered by tests
}}
/>
<Route
path={buildUrl(ResourceType.auditLogging) + SUB_URL_FOR_GENERAL_SETTINGS_EDIT}
render={() => {
Expand Down
2 changes: 2 additions & 0 deletions public/apps/configuration/constants.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ export const API_ENDPOINT_MULTITENANCY = API_PREFIX + '/multitenancy/tenant';
export const API_ENDPOINT_TENANCY_CONFIGS = API_ENDPOINT + '/tenancy/config';
export const API_ENDPOINT_SECURITYCONFIG = API_ENDPOINT + '/securityconfig';
export const API_ENDPOINT_INTERNALUSERS = API_ENDPOINT + '/internalusers';
export const API_ENDPOINT_INTERNALACCOUNTS = API_ENDPOINT + '/internalaccounts';
export const API_ENDPOINT_SERVICEACCOUNTS = API_ENDPOINT + '/serviceaccounts';
stephen-crawford marked this conversation as resolved.
Show resolved Hide resolved
export const API_ENDPOINT_AUDITLOGGING = API_ENDPOINT + '/audit';
export const API_ENDPOINT_AUDITLOGGING_UPDATE = API_ENDPOINT_AUDITLOGGING + '/config';
export const API_ENDPOINT_PERMISSIONS_INFO = API_PREFIX + '/restapiinfo';
Expand Down
220 changes: 220 additions & 0 deletions public/apps/configuration/panels/service-account-list.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,220 @@
/*
* Copyright OpenSearch Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/

import {
EuiBadge,
EuiButtonEmpty,
EuiFlexGroup,
EuiFlexItem,
EuiInMemoryTable,
EuiLink,
EuiPageBody,
EuiPageContent,
EuiPageContentHeader,
EuiPageContentHeaderSection,
EuiPageHeader,
EuiText,
EuiTitle,
Query,
} from '@elastic/eui';
import { Dictionary, difference, isEmpty, map } from 'lodash';
import React, { useState } from 'react';
import { getAuthInfo } from '../../../utils/auth-info-utils';
import { AppDependencies } from '../../types';
import { API_ENDPOINT_SERVICEACCOUNTS, DocLinks } from '../constants';
import { Action, ResourceType } from '../types';
import { EMPTY_FIELD_VALUE } from '../ui-constants';
import { useContextMenuState } from '../utils/context-menu';
import { ExternalLink, tableItemsUIProps, truncatedListView } from '../utils/display-utils';
import { getUserList, InternalUsersListing } from '../utils/internal-user-list-utils';
import { showTableStatusMessage } from '../utils/loading-spinner-utils';
import { buildHashUrl } from '../utils/url-builder';

export function dictView(items: Dictionary<string>) {
if (isEmpty(items)) {
return EMPTY_FIELD_VALUE;
}
return (
<EuiFlexGroup direction="column" style={{ margin: '1px' }}>
{map(items, (v, k) => (
<EuiText key={k} className={tableItemsUIProps.cssClassName}>
{k}: {`"${v}"`}
</EuiText>
))}
</EuiFlexGroup>
);
}

export function getColumns(currentUsername: string) {
return [
{
field: 'username',
name: 'Username',
render: (username: string) => (
<>
<a href={buildHashUrl(ResourceType.users, Action.edit, username)}>{username}</a>
{username === currentUsername && (
<>
&nbsp;
<EuiBadge>Current</EuiBadge>
</>
)}
</>
),
sortable: true,
},
{
field: 'backend_roles',
name: 'Backend roles',
render: truncatedListView(tableItemsUIProps),
},
{
field: 'attributes',
name: 'Attributes',
render: dictView,
truncateText: true,
},
];
}

export function ServiceAccountList(props: AppDependencies) {
const [userData, setUserData] = React.useState<InternalUsersListing[]>([]);
const [errorFlag, setErrorFlag] = React.useState(false);
const [selection, setSelection] = React.useState<InternalUsersListing[]>([]);
const [currentUsername, setCurrentUsername] = useState('');
const [loading, setLoading] = useState(false);
const [query, setQuery] = useState<Query | null>(null);

React.useEffect(() => {
const fetchData = async () => {
try {
setLoading(true);
const userDataPromise = getUserList(props.coreStart.http, ResourceType.serviceAccounts);
setCurrentUsername((await getAuthInfo(props.coreStart.http)).user_name);
setUserData(await userDataPromise);
} catch (e) {
console.log(e);
setErrorFlag(true);
} finally {
setLoading(false);
}
};

fetchData();
}, [props.coreStart.http]);

const actionsMenuItems = [
<EuiButtonEmpty
data-test-subj="edit"
key="edit"
onClick={() => {
window.location.href = buildHashUrl(ResourceType.users, Action.edit, selection[0].username);
}}
disabled={selection.length !== 1}
>
Edit
</EuiButtonEmpty>,
<EuiButtonEmpty
data-test-subj="duplicate"
key="duplicate"
onClick={() => {
window.location.href = buildHashUrl(
ResourceType.users,
Action.duplicate,
selection[0].username
);
}}
disabled={selection.length !== 1}
>
Duplicate
</EuiButtonEmpty>,
<EuiButtonEmpty
key="export"
disabled={selection.length !== 1}
href={
selection.length === 1
? `${props.coreStart.http.basePath.serverBasePath}${API_ENDPOINT_SERVICEACCOUNTS}/${selection[0].username}`
: ''
}
target="_blank"
>
Export JSON
</EuiButtonEmpty>,
];

const [actionsMenu, closeActionsMenu] = useContextMenuState('Actions', {}, actionsMenuItems);

return (
<>
<EuiPageHeader>
<EuiTitle size="l">
<h1>Service accounts</h1>
</EuiTitle>
</EuiPageHeader>
<EuiPageContent>
<EuiPageContentHeader>
<EuiPageContentHeaderSection>
<EuiTitle size="s">
<h3>
Service accounts
<span className="panel-header-count">
{' '}
({Query.execute(query || '', userData).length})
</span>
</h3>
</EuiTitle>
<EuiText size="s" color="subdued">
Here you have a list of special accounts that represent services like extensions,
samuelcostae marked this conversation as resolved.
Show resolved Hide resolved
plugins or other third party applications. You can map an account to a role from
<EuiLink href={buildHashUrl(ResourceType.roles)}>Roles</EuiLink>
“Manage mapping”
<ExternalLink href={DocLinks.BackendConfigurationAuthenticationDoc} />
</EuiText>
</EuiPageContentHeaderSection>
<EuiPageContentHeaderSection>
<EuiFlexGroup>
<EuiFlexItem>{actionsMenu}</EuiFlexItem>
</EuiFlexGroup>
</EuiPageContentHeaderSection>
</EuiPageContentHeader>
<EuiPageBody>
<EuiInMemoryTable
tableLayout={'auto'}
loading={userData === [] && !errorFlag}
columns={getColumns(currentUsername)}
// @ts-ignore
items={userData}
itemId={'username'}
pagination
search={{
box: { placeholder: 'Search service accounts' },
onChange: (arg) => {
setQuery(arg.query);
return true;

Check warning on line 205 in public/apps/configuration/panels/service-account-list.tsx

View check run for this annotation

Codecov / codecov/patch

public/apps/configuration/panels/service-account-list.tsx#L203-L205

Added lines #L203 - L205 were not covered by tests
},
}}
// @ts-ignore
selection={{ onSelectionChange: setSelection }}
sorting
error={
errorFlag ? 'Load data failed, please check the console log for more details.' : ''
}
message={showTableStatusMessage(loading, userData)}
/>
</EuiPageBody>
</EuiPageContent>
</>
);
}
Loading
Loading