Skip to content

Commit

Permalink
Adds method to register credential provider during data source plugin…
Browse files Browse the repository at this point in the history
… setup

Signed-off-by: Bandini Bhopi <[email protected]>
  • Loading branch information
bandinib-amzn committed Feb 8, 2024
1 parent ba298c7 commit 3ae69b9
Show file tree
Hide file tree
Showing 5 changed files with 107 additions and 11 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/

import { AuthMethodValues } from '../../server/types';

export type IAuthenticationMethodRegistery = Omit<
AuthenticationMethodRegistery,
'registerAuthenticationMethod'
>;

export class AuthenticationMethodRegistery {
private readonly authMethods = new Map<string, AuthMethodValues>();
/**
* Register a authMethods with function to return credentials inside the registry.
* Authentication Method can only be registered once. subsequent calls with the same method name will throw an error.
*/
public registerAuthenticationMethod(name: string, authMethodValues: AuthMethodValues) {
if (this.authMethods.has(name)) {
throw new Error(`Authentication method '${name}' is already registered`);
}
this.authMethods.set(name, authMethodValues);
}

public getAllAuthenticationMethods() {
return [...this.authMethods.values()];
}

public getAuthenticationMethod(name: string) {
return this.authMethods.get(name);
}
}
9 changes: 9 additions & 0 deletions src/plugins/data_source/server/auth_registry/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/

export {
IAuthenticationMethodRegistery,
AuthenticationMethodRegistery,
} from './authentication_methods_registry';
41 changes: 34 additions & 7 deletions src/plugins/data_source/server/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,19 +23,22 @@ import { LoggingAuditor } from './audit/logging_auditor';
import { CryptographyService, CryptographyServiceSetup } from './cryptography_service';
import { DataSourceService, DataSourceServiceSetup } from './data_source_service';
import { DataSourceSavedObjectsClientWrapper, dataSource } from './saved_objects';
import { DataSourcePluginSetup, DataSourcePluginStart } from './types';
import { AuthMethodValues, DataSourcePluginSetup, DataSourcePluginStart } from './types';
import { DATA_SOURCE_SAVED_OBJECT_TYPE } from '../common';

// eslint-disable-next-line @osd/eslint/no-restricted-paths
import { ensureRawRequest } from '../../../../src/core/server/http/router';
import { createDataSourceError } from './lib/error';
import { registerTestConnectionRoute } from './routes/test_connection';
import { AuthenticationMethodRegistery, IAuthenticationMethodRegistery } from './auth_registry';

export class DataSourcePlugin implements Plugin<DataSourcePluginSetup, DataSourcePluginStart> {
private readonly logger: Logger;
private readonly cryptographyService: CryptographyService;
private readonly dataSourceService: DataSourceService;
private readonly config$: Observable<DataSourcePluginConfigType>;
private started = false;
private authMethodsRegistry = new AuthenticationMethodRegistery();

constructor(private initializerContext: PluginInitializerContext<DataSourcePluginConfigType>) {
this.logger = this.initializerContext.logger.get();
Expand All @@ -44,7 +47,7 @@ export class DataSourcePlugin implements Plugin<DataSourcePluginSetup, DataSourc
this.config$ = this.initializerContext.config.create<DataSourcePluginConfigType>();
}

public async setup(core: CoreSetup) {
public async setup(core: CoreSetup<DataSourcePluginStart>) {
this.logger.debug('dataSource: Setup');

// Register data source saved object type
Expand Down Expand Up @@ -95,31 +98,54 @@ export class DataSourcePlugin implements Plugin<DataSourcePluginSetup, DataSourc
const auditTrailPromise = core.getStartServices().then(([coreStart]) => coreStart.auditTrail);

const dataSourceService: DataSourceServiceSetup = await this.dataSourceService.setup(config);

const authRegistryPromise = core.getStartServices().then(([, , selfStart]) => {
const dataSourcePluginStart = selfStart as DataSourcePluginStart;
return dataSourcePluginStart.getAuthenticationMethodRegistery();
});

// Register data source plugin context to route handler context
core.http.registerRouteHandlerContext(
'dataSource',
this.createDataSourceRouteHandlerContext(
dataSourceService,
cryptographyServiceSetup,
this.logger,
auditTrailPromise
auditTrailPromise,
authRegistryPromise
)
);

const router = core.http.createRouter();
registerTestConnectionRoute(router, dataSourceService, cryptographyServiceSetup);
registerTestConnectionRoute(
router,
dataSourceService,
cryptographyServiceSetup,
authRegistryPromise
);

const registerCredentialProvider = (name: string, authMethodValues: AuthMethodValues) => {
this.logger.debug(`Registered Credential Provider for authType = ${name}`);
if (this.started) {
throw new Error('cannot call `registerCredentialProvider` after service startup.');
}
this.authMethodsRegistry.registerAuthenticationMethod(name, authMethodValues);
};

return {
createDataSourceError: (e: any) => createDataSourceError(e),
dataSourceEnabled: () => config.enabled,
defaultClusterEnabled: () => config.defaultCluster,
registerCredentialProvider,
};
}

public start(core: CoreStart) {
this.logger.debug('dataSource: Started');

return {};
this.started = true;
return {
getAuthenticationMethodRegistery: () => this.authMethodsRegistry,
};
}

public stop() {
Expand All @@ -130,7 +156,8 @@ export class DataSourcePlugin implements Plugin<DataSourcePluginSetup, DataSourc
dataSourceService: DataSourceServiceSetup,
cryptography: CryptographyServiceSetup,
logger: Logger,
auditTrailPromise: Promise<AuditorFactory>
auditTrailPromise: Promise<AuditorFactory>,
authRegistryPromise: Promise<IAuthenticationMethodRegistery>
): IContextProvider<RequestHandler<unknown, unknown, unknown>, 'dataSource'> => {
return (context, req) => {
return {
Expand Down
4 changes: 3 additions & 1 deletion src/plugins/data_source/server/routes/test_connection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,13 @@ import { AuthType, DataSourceAttributes, SigV4ServiceName } from '../../common/d
import { DataSourceConnectionValidator } from './data_source_connection_validator';
import { DataSourceServiceSetup } from '../data_source_service';
import { CryptographyServiceSetup } from '../cryptography_service';
import { IAuthenticationMethodRegistery } from '../auth_registry';

export const registerTestConnectionRoute = (
router: IRouter,
dataSourceServiceSetup: DataSourceServiceSetup,
cryptography: CryptographyServiceSetup
cryptography: CryptographyServiceSetup,
authRegistryPromise: Promise<IAuthenticationMethodRegistery>
) => {
router.post(
{
Expand Down
31 changes: 28 additions & 3 deletions src/plugins/data_source/server/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,18 @@ import {
LegacyCallAPIOptions,
OpenSearchClient,
SavedObjectsClientContract,
OpenSearchDashboardsRequest,
} from 'src/core/server';
import { DataSourceAttributes } from '../common/data_sources';
import {
DataSourceAttributes,
AuthType,
UsernamePasswordTypedContent,
SigV4Content,
} from '../common/data_sources';

import { CryptographyServiceSetup } from './cryptography_service';
import { DataSourceError } from './lib/error';
import { IAuthenticationMethodRegistery } from './auth_registry';

export interface LegacyClientCallAPIParams {
endpoint: string;
Expand All @@ -29,6 +36,21 @@ export interface DataSourceClientParams {
testClientDataSourceAttr?: DataSourceAttributes;
}

export interface DataSourceCredentialsProviderOptions {
dataSourceAttr: DataSourceAttributes;
request?: OpenSearchDashboardsRequest;
cryptography?: CryptographyServiceSetup;
}

export type DataSourceCredentialsProvider = (
options: DataSourceCredentialsProviderOptions
) => Promise<UsernamePasswordTypedContent | SigV4Content>;

export interface AuthMethodValues {
credentialProvider: DataSourceCredentialsProvider;
authType: AuthType;
}

export interface DataSourcePluginRequestContext {
opensearch: {
getClient: (dataSourceId: string) => Promise<OpenSearchClient>;
Expand All @@ -55,6 +77,9 @@ export interface DataSourcePluginSetup {
createDataSourceError: (err: any) => DataSourceError;
dataSourceEnabled: () => boolean;
defaultClusterEnabled: () => boolean;
registerCredentialProvider: (name: string, authMethodValues: AuthMethodValues) => void;
}

export interface DataSourcePluginStart {
getAuthenticationMethodRegistery: () => IAuthenticationMethodRegistery;
}
// eslint-disable-next-line @typescript-eslint/no-empty-interface
export interface DataSourcePluginStart {}

0 comments on commit 3ae69b9

Please sign in to comment.