From a739c28c7f8a4c4941e89a08472bcced5d97c644 Mon Sep 17 00:00:00 2001 From: Louis Chu Date: Mon, 4 Jul 2022 21:49:15 -0700 Subject: [PATCH] [MD][Cred mngment] - PoC List all credentials (#8) 1. Move Credential Management within Stack Management 2. Find all credentials and list their names 3. Add credential creation button --- .../credential_management/common/index.ts | 6 +- .../credential_management/common/types.ts | 27 +++ .../opensearch_dashboards.json | 5 +- .../public/application.tsx | 23 --- .../public/components/app.tsx | 119 ----------- .../create_button/create_button.tsx | 140 +++++++++++++ .../public/components/create_button/index.tsx | 12 ++ .../create_credential_wizard.tsx | 10 + .../create_credential_wizard/index.tsx | 12 ++ .../credential_table/credentials_table.tsx | 195 ++++++++++++++++++ .../components/credential_table/index.tsx | 12 ++ .../public/components/index.tsx | 13 ++ .../public/components/types.ts | 23 +++ .../public/components/utils.ts | 54 +++++ .../credential_management/public/index.ts | 11 + .../public/management_app/index.tsx | 12 ++ .../mount_management_section.tsx | 114 ++++++++++ .../credential_management/public/plugin.ts | 69 +++++-- .../public/service/creation/config.ts | 117 +++++++++++ .../public/service/creation/index.ts | 13 ++ .../public/service/creation/manager.ts | 70 +++++++ .../service/credential_management_service.ts | 54 +++++ .../public/service/index.ts | 12 ++ .../credential_management/public/types.ts | 34 +++ .../server/credential/credential_manager.ts | 20 +- 25 files changed, 993 insertions(+), 184 deletions(-) create mode 100644 src/plugins/credential_management/common/types.ts delete mode 100644 src/plugins/credential_management/public/application.tsx delete mode 100644 src/plugins/credential_management/public/components/app.tsx create mode 100644 src/plugins/credential_management/public/components/create_button/create_button.tsx create mode 100644 src/plugins/credential_management/public/components/create_button/index.tsx create mode 100644 src/plugins/credential_management/public/components/create_credential_wizard/create_credential_wizard.tsx create mode 100644 src/plugins/credential_management/public/components/create_credential_wizard/index.tsx create mode 100644 src/plugins/credential_management/public/components/credential_table/credentials_table.tsx create mode 100644 src/plugins/credential_management/public/components/credential_table/index.tsx create mode 100644 src/plugins/credential_management/public/components/index.tsx create mode 100644 src/plugins/credential_management/public/components/types.ts create mode 100644 src/plugins/credential_management/public/components/utils.ts create mode 100644 src/plugins/credential_management/public/management_app/index.tsx create mode 100644 src/plugins/credential_management/public/management_app/mount_management_section.tsx create mode 100644 src/plugins/credential_management/public/service/creation/config.ts create mode 100644 src/plugins/credential_management/public/service/creation/index.ts create mode 100644 src/plugins/credential_management/public/service/creation/manager.ts create mode 100644 src/plugins/credential_management/public/service/credential_management_service.ts create mode 100644 src/plugins/credential_management/public/service/index.ts diff --git a/src/plugins/credential_management/common/index.ts b/src/plugins/credential_management/common/index.ts index 345de1ebc7db..638fb2ef003a 100644 --- a/src/plugins/credential_management/common/index.ts +++ b/src/plugins/credential_management/common/index.ts @@ -9,5 +9,9 @@ * GitHub history for details. */ +import { ICredential, IBasicAuthCredentialMaterial, IAWSIAMCredentialMaterial } from './types'; + export const PLUGIN_ID = 'credentialManagement'; -export const PLUGIN_NAME = 'credentialManagement'; +export const PLUGIN_NAME = 'Credential Management'; + +export { ICredential, IBasicAuthCredentialMaterial, IAWSIAMCredentialMaterial }; diff --git a/src/plugins/credential_management/common/types.ts b/src/plugins/credential_management/common/types.ts new file mode 100644 index 000000000000..76a1de019d1a --- /dev/null +++ b/src/plugins/credential_management/common/types.ts @@ -0,0 +1,27 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + * + * Any modifications Copyright OpenSearch Contributors. See + * GitHub history for details. + */ + +interface ICredential { + readonly credential_name: string; + readonly credential_type: string; + readonly credential_material: IBasicAuthCredentialMaterial | IAWSIAMCredentialMaterial; +} + +interface IBasicAuthCredentialMaterial { + readonly user_name: string; + readonly password: string; +} + +interface IAWSIAMCredentialMaterial { + readonly encrypted_aws_iam_credential: string; +} + +export { ICredential, IBasicAuthCredentialMaterial, IAWSIAMCredentialMaterial }; \ No newline at end of file diff --git a/src/plugins/credential_management/opensearch_dashboards.json b/src/plugins/credential_management/opensearch_dashboards.json index 7ce800d47573..fb3eca7a63a0 100644 --- a/src/plugins/credential_management/opensearch_dashboards.json +++ b/src/plugins/credential_management/opensearch_dashboards.json @@ -4,6 +4,7 @@ "opensearchDashboardsVersion": "opensearchDashboards", "server": true, "ui": true, - "requiredPlugins": ["management", "data", "navigation"], - "optionalPlugins": [] + "requiredPlugins": ["management", "data", "navigation", "urlForwarding"], + "optionalPlugins": [], + "requiredBundles": ["opensearchDashboardsReact"] } diff --git a/src/plugins/credential_management/public/application.tsx b/src/plugins/credential_management/public/application.tsx deleted file mode 100644 index 7e85e68cf1df..000000000000 --- a/src/plugins/credential_management/public/application.tsx +++ /dev/null @@ -1,23 +0,0 @@ -import React from 'react'; -import ReactDOM from 'react-dom'; -import { AppMountParameters, CoreStart } from '../../../core/public'; -import { AppPluginStartDependencies } from './types'; -import { CredentialManagementApp } from './components/app'; - -export const renderApp = ( - { notifications, http }: CoreStart, - { navigation }: AppPluginStartDependencies, - { appBasePath, element }: AppMountParameters -) => { - ReactDOM.render( - , - element - ); - - return () => ReactDOM.unmountComponentAtNode(element); -}; diff --git a/src/plugins/credential_management/public/components/app.tsx b/src/plugins/credential_management/public/components/app.tsx deleted file mode 100644 index 1461a4a5616c..000000000000 --- a/src/plugins/credential_management/public/components/app.tsx +++ /dev/null @@ -1,119 +0,0 @@ -import React, { useState } from 'react'; -import { i18n } from '@osd/i18n'; -import { FormattedMessage, I18nProvider } from '@osd/i18n/react'; -import { BrowserRouter as Router } from 'react-router-dom'; - -import { - EuiButton, - EuiHorizontalRule, - EuiPage, - EuiPageBody, - EuiPageContent, - EuiPageContentBody, - EuiPageContentHeader, - EuiPageHeader, - EuiTitle, - EuiText, -} from '@elastic/eui'; - -import { CoreStart } from '../../../../core/public'; -import { NavigationPublicPluginStart } from '../../../navigation/public'; - -import { PLUGIN_ID, PLUGIN_NAME } from '../../common'; - -interface CredentialManagementAppDeps { - basename: string; - notifications: CoreStart['notifications']; - http: CoreStart['http']; - navigation: NavigationPublicPluginStart; -} - -export const CredentialManagementApp = ({ - basename, - notifications, - http, - navigation, -}: CredentialManagementAppDeps) => { - // Use React hooks to manage state. - const [timestamp, setTimestamp] = useState(); - - const onClickHandler = () => { - // Use the core http service to make a response to the server API. - http.get('/api/credential_management/example').then((res) => { - setTimestamp(res.time); - // Use the core notifications service to display a success message. - notifications.toasts.addSuccess( - i18n.translate('credentialManagement.dataUpdated', { - defaultMessage: 'Data updated', - }) - ); - }); - }; - - // Render the application DOM. - // Note that `navigation.ui.TopNavMenu` is a stateful component exported on the `navigation` plugin's start contract. - return ( - - - <> - - - - - -

- -

-
-
- - - -

- -

-
-
- - -

- -

- -

- -

- - - -
-
-
-
-
- -
-
- ); -}; diff --git a/src/plugins/credential_management/public/components/create_button/create_button.tsx b/src/plugins/credential_management/public/components/create_button/create_button.tsx new file mode 100644 index 000000000000..470cecdcc65d --- /dev/null +++ b/src/plugins/credential_management/public/components/create_button/create_button.tsx @@ -0,0 +1,140 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + * + * Any modifications Copyright OpenSearch Contributors. See + * GitHub history for details. + */ + +// @ts-ignore +import { euiColorAccent } from '@elastic/eui/dist/eui_theme_light.json'; +import React, { Component, Fragment } from 'react'; + +import { + EuiBadge, + EuiButton, + EuiContextMenuItem, + EuiContextMenuPanel, + EuiDescriptionList, + EuiDescriptionListDescription, + EuiDescriptionListTitle, + EuiPopover, +} from '@elastic/eui'; + +import { FormattedMessage } from '@osd/i18n/react'; + +interface State { + isPopoverOpen: boolean; +} + +interface Props { + options: Array<{ + text: string; + description?: string; + testSubj?: string; + isBeta?: boolean; + onClick: () => void; + }>; +} + +export class CreateButton extends Component { + public state = { + isPopoverOpen: false, + }; + + public render() { + const { options, children } = this.props; + const { isPopoverOpen } = this.state; + + if (!options || !options.length) { + return null; + } + + if (options.length === 1) { + return ( + + {children} + + ); + } + + const button = ( + + {children} + + ); + + if (options.length > 1) { + return ( + + { + return ( + + + + {option.text} + {option.isBeta ? {this.renderBetaBadge()} : null} + + + {option.description} + + + + ); + })} + /> + + ); + } + } + + private togglePopover = () => { + this.setState({ + isPopoverOpen: !this.state.isPopoverOpen, + }); + }; + + private closePopover = () => { + this.setState({ + isPopoverOpen: false, + }); + }; + + private renderBetaBadge = () => { + return ( + + + + ); + }; +} diff --git a/src/plugins/credential_management/public/components/create_button/index.tsx b/src/plugins/credential_management/public/components/create_button/index.tsx new file mode 100644 index 000000000000..11791c11a0d3 --- /dev/null +++ b/src/plugins/credential_management/public/components/create_button/index.tsx @@ -0,0 +1,12 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + * + * Any modifications Copyright OpenSearch Contributors. See + * GitHub history for details. + */ + +export { CreateButton } from './create_button'; diff --git a/src/plugins/credential_management/public/components/create_credential_wizard/create_credential_wizard.tsx b/src/plugins/credential_management/public/components/create_credential_wizard/create_credential_wizard.tsx new file mode 100644 index 000000000000..7e6a83d98779 --- /dev/null +++ b/src/plugins/credential_management/public/components/create_credential_wizard/create_credential_wizard.tsx @@ -0,0 +1,10 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + * + * Any modifications Copyright OpenSearch Contributors. See + * GitHub history for details. + */ diff --git a/src/plugins/credential_management/public/components/create_credential_wizard/index.tsx b/src/plugins/credential_management/public/components/create_credential_wizard/index.tsx new file mode 100644 index 000000000000..5017dcad6273 --- /dev/null +++ b/src/plugins/credential_management/public/components/create_credential_wizard/index.tsx @@ -0,0 +1,12 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + * + * Any modifications Copyright OpenSearch Contributors. See + * GitHub history for details. + */ + +export { CreateCredentialWizardWithRouter } from './create_credential_wizard'; diff --git a/src/plugins/credential_management/public/components/credential_table/credentials_table.tsx b/src/plugins/credential_management/public/components/credential_table/credentials_table.tsx new file mode 100644 index 000000000000..2f59d4da00d7 --- /dev/null +++ b/src/plugins/credential_management/public/components/credential_table/credentials_table.tsx @@ -0,0 +1,195 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + * + * Any modifications Copyright OpenSearch Contributors. See + * GitHub history for details. + */ + +import React from 'react'; +import { withRouter, RouteComponentProps } from 'react-router-dom'; + +import { i18n } from '@osd/i18n'; +import { FormattedMessage } from '@osd/i18n/react'; + +import { + EuiBadge, + EuiButtonEmpty, + EuiFlexGroup, + EuiFlexItem, + EuiInMemoryTable, + EuiSpacer, + EuiText, + EuiBadgeGroup, + EuiPageContent, + EuiTitle, + // EuiButton, +} from '@elastic/eui'; + +import { + reactRouterNavigate, + useOpenSearchDashboards, +} from '../../../../opensearch_dashboards_react/public'; + +import { CredentialManagementContext } from '../../types'; +import { getCredentials } from '../utils'; +import { CredentialsTableItem, CredentialCreationOption } from '../types'; +import { CreateButton } from '../create_button'; + +const pagination = { + initialPageSize: 10, + pageSizeOptions: [5, 10, 25, 50], +}; + +const sorting = { + sort: { + field: 'credentialName', + direction: 'asc' as const, + }, +}; + +const search = { + box: { + incremental: true, + schema: { + fields: { title: { type: 'string' } }, + }, + }, +}; + +// const ariaRegion = i18n.translate('credentialManagement.editIndexPatternLiveRegionAriaLabel', { +// defaultMessage: , +// }); + +const title = i18n.translate('credentialManagement.credentialsTable.title', { + defaultMessage: 'Credentials', +}); + +interface Props extends RouteComponentProps { + canSave: boolean; +} + +export const CredentialsTable = ({ canSave, history }: Props) => { + const [credentials, setCredentials] = React.useState([]); + const [creationOptions, setCreationOptions] = React.useState([]); + + const { + // setBreadcrumbs, + savedObjects, + uiSettings, + // dataSourceManagementStart, + // chrome, + // docLinks, + // application, + // http, + // getMlCardState, + // data, + } = useOpenSearchDashboards().services; + + // console.warn("services: ", useOpenSearchDashboards().services); + + const columns = [ + { + field: 'credentialName', + name: 'Credential', + render: ( + name: string, + index: { + id: string; + tags?: Array<{ + key: string; + name: string; + }>; + } + ) => ( + <> + + {name} + +   + + {index.tags && + index.tags.map(({ key: tagKey, name: tagName }) => ( + {tagName} + ))} + + + ), + dataType: 'string' as const, + sortable: ({ sort }: { sort: string }) => sort, + }, + ]; + + React.useEffect(() => { + (async function () { + const fetchedCredentials: CredentialsTableItem[] = await getCredentials( + savedObjects.client, + uiSettings.get('defaultIndex') + ); + setCredentials(fetchedCredentials); + })(); + }, [ + history.push, + credentials.length, + uiSettings, + savedObjects.client, + ]); + + // TODO: Update it + creationOptions.push({ + text: 'Create', + onClick(): void { + throw new Error('Function not implemented.'); + }, + }); + + const createButton = canSave ? ( + + + + ) : ( + <> + ); + + return ( + // + + + + +

{title}

+
+ + +

+ +

+
+
+ {createButton} +
+ + +
+ ); +}; + +export const CredentialsTableWithRouter = withRouter(CredentialsTable); diff --git a/src/plugins/credential_management/public/components/credential_table/index.tsx b/src/plugins/credential_management/public/components/credential_table/index.tsx new file mode 100644 index 000000000000..8f8e4b0ab3a0 --- /dev/null +++ b/src/plugins/credential_management/public/components/credential_table/index.tsx @@ -0,0 +1,12 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + * + * Any modifications Copyright OpenSearch Contributors. See + * GitHub history for details. + */ + +export { CredentialsTableWithRouter } from './credentials_table'; diff --git a/src/plugins/credential_management/public/components/index.tsx b/src/plugins/credential_management/public/components/index.tsx new file mode 100644 index 000000000000..b00f3788388c --- /dev/null +++ b/src/plugins/credential_management/public/components/index.tsx @@ -0,0 +1,13 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + * + * Any modifications Copyright OpenSearch Contributors. See + * GitHub history for details. + */ + +export { CredentialsTableWithRouter } from './credential_table'; +export { CreateCredentialWizardWithRouter } from './create_credential_wizard'; diff --git a/src/plugins/credential_management/public/components/types.ts b/src/plugins/credential_management/public/components/types.ts new file mode 100644 index 000000000000..1247a4b912a6 --- /dev/null +++ b/src/plugins/credential_management/public/components/types.ts @@ -0,0 +1,23 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + * + * Any modifications Copyright OpenSearch Contributors. See + * GitHub history for details. + */ + +// TODO: Refactor models +export interface CredentialCreationOption { + text: string; + description?: string; + onClick: () => void; +} + +export interface CredentialsTableItem { + id: string; + credentialName: string; + sort: string; +} diff --git a/src/plugins/credential_management/public/components/utils.ts b/src/plugins/credential_management/public/components/utils.ts new file mode 100644 index 000000000000..65529dd75904 --- /dev/null +++ b/src/plugins/credential_management/public/components/utils.ts @@ -0,0 +1,54 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + * + * Any modifications Copyright OpenSearch Contributors. See + * GitHub history for details. + */ + +import { SavedObjectsClientContract } from 'src/core/public'; +import { ICredential } from '../../common'; +// import { CredentialManagementStart } from '../plugin'; + +export async function getCredentials( + savedObjectsClient: SavedObjectsClientContract, + defaultIndex: string + // credentialManagementStart: CredentialManagementStart +) { +return await ( + savedObjectsClient + .find({ + type: 'credential', + fields: ['id', 'credential_name', 'credential_type'], + perPage: 10000, + }) + .then((response) => + response.savedObjects + .map((source) => { + const id = source.id; + const title = source.get('title'); + const credentialName = source.get('credential_name'); + const credentialType = source.get('credential_type'); + return { + id, + title, + credentialName, + credentialType, + sort: `${credentialName}`, + }; + }) + .sort((a, b) => { + if (a.sort < b.sort) { + return -1; + } else if (a.sort > b.sort) { + return 1; + } else { + return 0; + } + }) + ) || [] + ); +} diff --git a/src/plugins/credential_management/public/index.ts b/src/plugins/credential_management/public/index.ts index aa2d3fdb9c91..9fdf9d41a177 100644 --- a/src/plugins/credential_management/public/index.ts +++ b/src/plugins/credential_management/public/index.ts @@ -1,3 +1,14 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + * + * Any modifications Copyright OpenSearch Contributors. See + * GitHub history for details. + */ + import './index.scss'; import { CredentialManagementPlugin } from './plugin'; diff --git a/src/plugins/credential_management/public/management_app/index.tsx b/src/plugins/credential_management/public/management_app/index.tsx new file mode 100644 index 000000000000..fe9249cb70e3 --- /dev/null +++ b/src/plugins/credential_management/public/management_app/index.tsx @@ -0,0 +1,12 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + * + * Any modifications Copyright OpenSearch Contributors. See + * GitHub history for details. + */ + +export { mountManagementSection } from './mount_management_section'; diff --git a/src/plugins/credential_management/public/management_app/mount_management_section.tsx b/src/plugins/credential_management/public/management_app/mount_management_section.tsx new file mode 100644 index 000000000000..0d2b919b854d --- /dev/null +++ b/src/plugins/credential_management/public/management_app/mount_management_section.tsx @@ -0,0 +1,114 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + * + * Any modifications Copyright OpenSearch Contributors. See + * GitHub history for details. + */ + +import React from 'react'; +import ReactDOM from 'react-dom'; +import { Router, Switch, Route } from 'react-router-dom'; + +// TODO: Clean up this file after creation UX added +// import { i18n } from '@osd/i18n'; +import { I18nProvider } from '@osd/i18n/react'; + +// import { EuiIconType } from '@elastic/eui/src/components/icon/icon'; +// import { OpenSearchDashboardsContextProvider } from '../../../opensearch_dashboards_react/public'; +import { StartServicesAccessor } from 'src/core/public'; +import { DataPublicPluginStart } from '/src/plugins/data/public'; +import { ManagementAppMountParams } from '../../../management/public'; +// import { +// IndexPatternTableWithRouter, +// EditIndexPatternContainer, +// CreateEditFieldContainer, +// CreateIndexPatternWizardWithRouter, +// } from '../components'; +// import { CredentialManagementStart } from '../plugin'; +import { CredentialsTableWithRouter, CreateIndexPatternWizardWithRouter } from '../components'; +import { CredentialManagementContext } from '../types'; +import { OpenSearchDashboardsContextProvider } from '../../../opensearch_dashboards_react/public'; + +export interface CredentialManagementStartDependencies { + data: DataPublicPluginStart; +} + +export async function mountManagementSection( + getStartServices: StartServicesAccessor, + params: ManagementAppMountParams +// getMlCardState: () => MlCardState +) { + const [ + { chrome, application, savedObjects, uiSettings, notifications, overlays, http, docLinks }, + { data }, + // indexPatternManagementStart, + ] = await getStartServices(); +// const canSave = Boolean(application.capabilities.indexPatterns.save); + +// if (!canSave) { +// chrome.setBadge(readOnlyBadge); +// } + + const deps: CredentialManagementContext = { + chrome, + application, + savedObjects, + uiSettings, + notifications, + overlays, + http, + docLinks, + data, + // indexPatternManagementStart: indexPatternManagementStart as IndexPatternManagementStart, + // setBreadcrumbs: params.setBreadcrumbs, + // getMlCardState, + }; + + // ReactDOM.render( + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // , + // params.element + // ); + + ReactDOM.render( + + + + + + + + {/* + + */} + + + + , + params.element + ); + + return () => { + chrome.docTitle.reset(); + ReactDOM.unmountComponentAtNode(params.element); + }; +} diff --git a/src/plugins/credential_management/public/plugin.ts b/src/plugins/credential_management/public/plugin.ts index 794e84339703..8f830910d8f4 100644 --- a/src/plugins/credential_management/public/plugin.ts +++ b/src/plugins/credential_management/public/plugin.ts @@ -1,4 +1,17 @@ -import { i18n } from '@osd/i18n'; +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + * + * Any modifications Copyright OpenSearch Contributors. See + * GitHub history for details. + */ + +// import { i18n } from '@osd/i18n'; +import { DataPublicPluginStart } from 'src/plugins/data/public'; + import { AppMountParameters, CoreSetup, CoreStart, Plugin } from '../../../core/public'; import { CredentialManagementPluginSetup, @@ -7,34 +20,46 @@ import { } from './types'; import { PLUGIN_NAME } from '../common'; +import { ManagementSetup } from '../../management/public'; +import { UrlForwardingSetup } from '../../url_forwarding/public'; + +import { CredentialManagementService } from './service'; + +export interface CredentialManagementSetupDependencies { + management: ManagementSetup; + urlForwarding: UrlForwardingSetup; +} + +export interface CredentialManagementStartDependencies { + data: DataPublicPluginStart; +} + export class CredentialManagementPlugin implements Plugin { - public setup(core: CoreSetup): CredentialManagementPluginSetup { - // Register an application into the side navigation menu - core.application.register({ + private readonly credentialManagementService = new CredentialManagementService(); + + public setup ( + core: CoreSetup, + { management, urlForwarding}: CredentialManagementSetupDependencies + ): CredentialManagementPluginSetup { + const opensearchDashboardsSection = management.sections.section.opensearchDashboards; + + if (!opensearchDashboardsSection) { + throw new Error('`opensearchDashboards` management section not found.'); + } + + opensearchDashboardsSection.registerApp({ id: 'credentialManagement', title: PLUGIN_NAME, - async mount(params: AppMountParameters) { - // Load application bundle - const { renderApp } = await import('./application'); - // Get start services as specified in opensearch_dashboards.json - const [coreStart, depsStart] = await core.getStartServices(); - // Render the application - return renderApp(coreStart, depsStart as AppPluginStartDependencies, params); + order: 0, + mount: async (params) => { + const { mountManagementSection } = await import('./management_app'); + + return mountManagementSection(core.getStartServices, params); }, }); - // Return methods that should be available to other plugins - return { - getGreeting() { - return i18n.translate('credentialManagement.greetingText', { - defaultMessage: 'Hello from {name}!', - values: { - name: PLUGIN_NAME, - }, - }); - }, - }; + return this.credentialManagementService.setup({ httpClient: core.http }); } public start(core: CoreStart): CredentialManagementPluginStart { diff --git a/src/plugins/credential_management/public/service/creation/config.ts b/src/plugins/credential_management/public/service/creation/config.ts new file mode 100644 index 000000000000..8490bd7ad9fc --- /dev/null +++ b/src/plugins/credential_management/public/service/creation/config.ts @@ -0,0 +1,117 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + * + * Any modifications Copyright OpenSearch Contributors. See + * GitHub history for details. + */ + +// TODO: Clean up this file after creation UX added +import { i18n } from '@osd/i18n'; +// import { MatchedItem } from '../../components/create_credential_wizard/types'; + +const credentialTypeName = i18n.translate( + 'credentialManagement.editCredential.defaultTypeName', + { defaultMessage: 'credential' } +); + +const credentialButtonText = i18n.translate( + 'credentialManagement.editCredential.defaultButtonText', + { defaultMessage: 'Standard credential' } +); + +// const indexPatternButtonDescription = i18n.translate( +// 'indexPatternManagement.editIndexPattern.createIndex.defaultButtonDescription', +// { defaultMessage: 'Perform full aggregations against any data' } +// ); + +export type UrlHandler = (url: string) => void; + +// TODO: Revisit it +export interface CredentialCreationOption { + text: string; + description: string; + testSubj: string; + onClick: () => void; + isBeta?: boolean; +} + +export class CredentialCreationConfig { + public readonly key = 'default'; + + protected type?: string; + protected name: string; + protected showSystemIndices: boolean; + protected httpClient: object | null; + protected isBeta: boolean; + + constructor({ + type = undefined, + name = credentialTypeName, + showSystemIndices = true, + httpClient = null, + isBeta = false, + }: { + type?: string; + name?: string; + showSystemIndices?: boolean; + httpClient?: object | null; + isBeta?: boolean; + }) { + this.type = type; + this.name = name; + this.showSystemIndices = showSystemIndices; + this.httpClient = httpClient; + this.isBeta = isBeta; + } + + public getIndexPatternCreationOption(urlHandler: UrlHandler): CredentialCreationOption { + return { + text: credentialButtonText, + description: `getIndexPatternCreationOption`, + testSubj: `createStandardCredentialButton`, + onClick: () => { + urlHandler('/create'); + }, + }; + } + + // public getIndexPatternType() { + // return this.type; + // } + + // public getIndexPatternName() { + // return this.name; + // } + + // public getIsBeta() { + // return this.isBeta; + // } + + // public getShowSystemIndices() { + // return this.showSystemIndices; + // } + + // public getIndexTags(indexName: string) { + // return []; + // } + + // public checkIndicesForErrors(indices: MatchedItem[]) { + // return undefined; + // } + + // public getIndexPatternMappings() { + // return {}; + // } + + public renderPrompt() { + return null; + } + + public getFetchForWildcardOptions() { + return {}; + } +} diff --git a/src/plugins/credential_management/public/service/creation/index.ts b/src/plugins/credential_management/public/service/creation/index.ts new file mode 100644 index 000000000000..7da960ef50a7 --- /dev/null +++ b/src/plugins/credential_management/public/service/creation/index.ts @@ -0,0 +1,13 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + * + * Any modifications Copyright OpenSearch Contributors. See + * GitHub history for details. + */ + +export { CredentialCreationConfig, CredentialCreationOption } from './config'; +export { CredentialCreationManager } from './manager'; diff --git a/src/plugins/credential_management/public/service/creation/manager.ts b/src/plugins/credential_management/public/service/creation/manager.ts new file mode 100644 index 000000000000..68e90b684506 --- /dev/null +++ b/src/plugins/credential_management/public/service/creation/manager.ts @@ -0,0 +1,70 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + * + * Any modifications Copyright OpenSearch Contributors. See + * GitHub history for details. + */ + +import { HttpSetup } from '../../../../../core/public'; +// import { CredentialCreationConfig, UrlHandler, CredentialCreationOption } from './config'; + +// TODO: Revisit it +export class CredentialCreationManager { +// private configs: CredentialCreationConfig[] = []; + setup(httpClient: HttpSetup) { + return { + // TODO - Add Config + // addCreationConfig: (Config: typeof CredentialCreationConfig) => { + // const config = new Config({ httpClient }); + + // if (this.configs.findIndex((c) => c.key === config.key) !== -1) { + // throw new Error(`${config.key} exists in CredentialCreationManager.`); + // } + + // this.configs.push(config); + // }, + }; + } + + start() { + // const getType = (key: string | undefined): CredentialCreationConfig => { + // if (key) { + // const index = this.configs.findIndex((config) => config.key === key); + // const config = this.configs[index]; + + // if (config) { + // return config; + // } else { + // throw new Error(`Index pattern creation type not found: ${key}`); + // } + // } else { + // return getType('default'); + // } + // }; + + // return { + // getType, + // getIndexPatternCreationOptions: async (urlHandler: UrlHandler) => { + // const options: CredentialCreationOption[] = []; + + // await Promise.all( + // this.configs.map(async (config) => { + // const option = config.getCredentialCreationOption + // ? await config.getCredentialCreationOption(urlHandler) + // : null; + // if (option) { + // options.push(option); + // } + // }) + // ); + + // return options; + // }, + // }; + return {}; + } +} diff --git a/src/plugins/credential_management/public/service/credential_management_service.ts b/src/plugins/credential_management/public/service/credential_management_service.ts new file mode 100644 index 000000000000..639c5417ffe9 --- /dev/null +++ b/src/plugins/credential_management/public/service/credential_management_service.ts @@ -0,0 +1,54 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + * + * Any modifications Copyright OpenSearch Contributors. See + * GitHub history for details. + */ + +import { HttpSetup } from '../../../../core/public'; +import { CredentialCreationConfig, CredentialCreationManager } from './creation'; + +interface SetupDependencies { + httpClient: HttpSetup; +} + +/** + * credential management service + * + * @internal + */ +export class CredentialManagementService { + credentialCreationManager: CredentialCreationManager; + + constructor() { + // TODO: Refactor with Singleton + this.credentialCreationManager = new CredentialCreationManager(); + } + + public setup({ httpClient }: SetupDependencies) { + const creationManagerSetup = this.credentialCreationManager.setup(httpClient); + return { + creation: creationManagerSetup, + // TODO: Add list, editor, and env service setup + }; + } + + public start() { + return { + creation: this.credentialCreationManager.start(), + // TODO: Add list config and editor + }; + } + + public stop() { + // nothing to do here yet. + } +} + +// /** @internal */ +export type CredentialManagementServiceSetup = ReturnType; +export type CredentialManagementServiceStart = ReturnType; diff --git a/src/plugins/credential_management/public/service/index.ts b/src/plugins/credential_management/public/service/index.ts new file mode 100644 index 000000000000..0c30ad8eaa3c --- /dev/null +++ b/src/plugins/credential_management/public/service/index.ts @@ -0,0 +1,12 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + * + * Any modifications Copyright OpenSearch Contributors. See + * GitHub history for details. + */ + +export { CredentialManagementService } from './credential_management_service'; diff --git a/src/plugins/credential_management/public/types.ts b/src/plugins/credential_management/public/types.ts index 16a55ec3e6be..cd68072d3ae5 100644 --- a/src/plugins/credential_management/public/types.ts +++ b/src/plugins/credential_management/public/types.ts @@ -1,3 +1,25 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + * + * Any modifications Copyright OpenSearch Contributors. See + * GitHub history for details. + */ + +import { + ChromeStart, + ApplicationStart, + IUiSettingsClient, + OverlayStart, + SavedObjectsStart, + NotificationsStart, + DocLinksStart, + HttpSetup, +} from 'src/core/public'; +import { DataPublicPluginStart } from 'src/plugins/data/public'; import { NavigationPublicPluginStart } from '../../navigation/public'; export interface CredentialManagementPluginSetup { @@ -9,3 +31,15 @@ export interface CredentialManagementPluginStart {} export interface AppPluginStartDependencies { navigation: NavigationPublicPluginStart; } + +export interface CredentialManagementContext { + chrome: ChromeStart; + application: ApplicationStart; + savedObjects: SavedObjectsStart; + uiSettings: IUiSettingsClient; + notifications: NotificationsStart; + overlays: OverlayStart; + http: HttpSetup; + docLinks: DocLinksStart; + data: DataPublicPluginStart; +} diff --git a/src/plugins/credential_management/server/credential/credential_manager.ts b/src/plugins/credential_management/server/credential/credential_manager.ts index 7409ca18c62c..0e653f86ac77 100644 --- a/src/plugins/credential_management/server/credential/credential_manager.ts +++ b/src/plugins/credential_management/server/credential/credential_manager.ts @@ -11,27 +11,13 @@ import { OpenSearchDashboardsRequest } from 'opensearch-dashboards/server'; import { CryptoCli } from '../crypto'; - -interface Credential { - readonly credential_name: string; - readonly credential_type: string; - readonly credential_material: BasicAuthCredentialMaterial | AWSIAMCredentialMaterial; -} - -interface BasicAuthCredentialMaterial { - readonly user_name: string; - readonly password: string; -} - -interface AWSIAMCredentialMaterial { - readonly encrypted_aws_iam_credential: string; -} +import { IBasicAuthCredentialMaterial, IAWSIAMCredentialMaterial } from '../../common'; // TODO: Refactor handler, add logger, etc export async function createHandler(request: OpenSearchDashboardsRequest) { const cryptoCli = CryptoCli.getInstance(); if (request.body.credential_type === 'basic_auth') { - const basicAuthCredentialMaterial: BasicAuthCredentialMaterial = { + const basicAuthCredentialMaterial: IBasicAuthCredentialMaterial = { user_name: request.body.basic_auth_credential_JSON.user_name, password: await cryptoCli.encrypt(request.body.basic_auth_credential_JSON.password), }; @@ -41,7 +27,7 @@ export async function createHandler(request: OpenSearchDashboardsRequest) { credential_material: basicAuthCredentialMaterial, }; } else if (request.body.credential_type === 'aws_iam_credential') { - const aWSIAMCredentialMaterial: AWSIAMCredentialMaterial = { + const aWSIAMCredentialMaterial: IAWSIAMCredentialMaterial = { encrypted_aws_iam_credential: await cryptoCli.encrypt( request.body.basic_auth_credential_JSON.password ),