Skip to content

Commit

Permalink
use credential manager to decrypt password
Browse files Browse the repository at this point in the history
Signed-off-by: Zhongnan Su <[email protected]>
  • Loading branch information
zhongnansu committed Jul 21, 2022
1 parent 282e578 commit 1a8e74b
Show file tree
Hide file tree
Showing 11 changed files with 74 additions and 41 deletions.
14 changes: 12 additions & 2 deletions src/core/server/core_route_handler_context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ import {
import { Auditor } from './audit_trail';
import { InternalUiSettingsServiceStart, IUiSettingsClient } from './ui_settings';
import { InternalOpenSearchDataServiceStart } from './opensearch_data/types';
import { ConnectionError } from '@opensearch-project/opensearch/lib/errors';

class CoreOpenSearchRouteHandlerContext {
#client?: IScopedClusterClient;
Expand Down Expand Up @@ -74,8 +75,17 @@ class CoreOpenSearchDataSourceRouteHandlerContext {
constructor(private readonly opensearchDataStart: InternalOpenSearchDataServiceStart) {}

public async getClient(dataSourceId: string) {
const client = await this.opensearchDataStart.client.asDataSource(dataSourceId);
return client;
try {
const client = await this.opensearchDataStart.client.asDataSource(dataSourceId);
return client;
} catch (error) {
if (error.message) {
throw new Error(error.message);
} else
throw new Error(
`Fail to get data source client for dataSource id: [${dataSourceId}]. Detail: ${error}`
);
}
}
}

Expand Down
57 changes: 42 additions & 15 deletions src/core/server/opensearch_data/client/data_source_client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { Client } from '@opensearch-project/opensearch';
import { Logger } from '../../logging';
import { OpenSearchClient, OpenSearchClientConfig } from '../../opensearch/client';
import { SavedObjectsClientContract } from '../../saved_objects/types';
import { CryptoCli } from '../../../../../src/plugins/credential_management/server/crypto/cli/crypto_cli';

/**
* TODO: update doc
Expand Down Expand Up @@ -39,6 +40,17 @@ export interface ICustomDataSourceClient extends IDdataSourceClient {
close: () => Promise<void>;
}

// TODO: tmp
interface DataSourceInfo {
endpoint: string;
credentialId: string;
}

interface CredentialInfo {
username: string;
password: string;
}

export class DataSourceClient implements ICustomDataSourceClient {
public dataSourceClientsPool: Map<string, Client>;
private savedObjectClient: SavedObjectsClientContract;
Expand All @@ -57,26 +69,14 @@ export class DataSourceClient implements ICustomDataSourceClient {
// 2. throw error if isDataSourceEnabled == false, while API is called
}
async asDataSource(dataSourceId: string) {
// 1. fetch meta info of data source using saved_object client
const dataSource = await this.savedObjectClient.get('data-source', dataSourceId);

// 2. TODO: parse to DataSource object, need update once dataSource type is in place
const dataSourceObj = dataSource!.attributes as any;
const url = dataSourceObj.endpoint.url;
/**
* TODO:
* credential manager will provide "decrypt(authId: string)" to return auth
* Example code: cosnt {username, password} = credentialManager.decrpt(dataSourceObj.authId)
*/
const username = dataSourceObj.endpoint.credentials.username;
const password = dataSourceObj.endpoint.credentials.password;

const { endpoint, credentialId } = await this.getDataSourceInfo(dataSourceId);
const { username, password } = await this.getCredentialInfo(credentialId);
// 2. build/find client and return
let dataSourceClient = this.dataSourceClientsPool.get(dataSourceId);
if (!dataSourceClient) {
// TODO: make use of existing default clientConfig to build client
dataSourceClient = new Client({
node: url,
node: endpoint,
auth: {
username,
password,
Expand All @@ -88,6 +88,33 @@ export class DataSourceClient implements ICustomDataSourceClient {
return dataSourceClient;
}

private async getDataSourceInfo(dataSourceId: string): Promise<DataSourceInfo> {
// 1. fetch meta info of data source using saved_object client
const dataSource = await this.savedObjectClient.get('data-source', dataSourceId);
// 2. TODO: parse to DataSource object, need update once dataSource type is in place
const dataSourceObj = dataSource!.attributes as any;
const endpoint = dataSourceObj.endpoint;
const credentialId = dataSource!.references[0].id;

return { endpoint, credentialId };
}

private async getCredentialInfo(credentialId: string): Promise<CredentialInfo> {
/**
* TODO:
* credential manager will provide "decrypt(authId: string)" to return auth
* Example code: cosnt {username, password} = credentialManager.decrpt(dataSourceObj.authId)
*/
const credential = await this.savedObjectClient.get('credential', credentialId);
const credentialObj = credential!.attributes as any;
const { user_name: username, password: encryptedPassword } = credentialObj.credential_material;

const password = await CryptoCli.getInstance().decrypt(
Buffer.from(encryptedPassword, 'base64')
);
return { username, password };
}

// close anything in pool
public async close() {
if (this.isClosed) {
Expand Down
17 changes: 5 additions & 12 deletions src/core/server/opensearch_data/opensearch_data_service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,26 +14,19 @@ import { CoreContext } from '../core_context';
import { Logger } from '../logging';
import { OpenSearchClientConfig } from '../opensearch/client';
import { OpenSearchConfig, OpenSearchConfigType } from '../opensearch/opensearch_config';
import { OpenSearchService } from '../opensearch/opensearch_service';
import {
InternalOpenSearchServiceSetup,
InternalOpenSearchServiceStart,
} from '../opensearch/types';
import { pollOpenSearchNodesVersion } from '../opensearch/version_check/ensure_opensearch_version';
import {
InternalSavedObjectsServiceSetup,
InternalSavedObjectsServiceStart,
SavedObjectsClient,
} from '../saved_objects';
import { InternalSavedObjectsServiceStart, SavedObjectsClient } from '../saved_objects';
import { SavedObjectsClientContract } from '../types';
import { DataSourceClient } from './client/data_source_client';
import { InternalOpenSearchDataServiceSetup, InternalOpenSearchDataServiceStart } from './types';

interface StartDeps {
savedObjects: InternalSavedObjectsServiceStart;
auditTrail: AuditTrailStart;
}

export class OpenSearchDataService implements CoreService<any, any> {
export class OpenSearchDataService
implements CoreService<InternalOpenSearchDataServiceSetup, InternalOpenSearchDataServiceStart> {
private readonly log: Logger;
private readonly config$: Observable<OpenSearchConfig>;
private auditorFactory?: AuditorFactory;
Expand Down Expand Up @@ -76,7 +69,7 @@ export class OpenSearchDataService implements CoreService<any, any> {
this.dataSourceClient = this.createDataSourceClient('data-source', config);

return {
dataSourceClient: this.dataSourceClient,
client: this.dataSourceClient,
};
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ export class CryptoCli {
return result.result.toString('base64');
}

public async decrypt(encrypted: Buffer) {
public async decrypt(encrypted: Buffer): Promise<string> {
const result = await this._decrypt(this._keyring, encrypted);
return result.plaintext.toString();
}
Expand All @@ -80,7 +80,7 @@ export class CryptoCli {
return './crypto_material';
}

// TODO: Support configurable crypto materials file path
// TODO: Support configurable crypto materials file path
public static generateCryptoMaterials(keyName: string, keyNamespace: string) {
const cryptoMaterials = {
keyName,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"keyName":"aes-name","keyNamespace":"aes-namespace","unencryptedMasterKey":{"type":"Buffer","data":[82,211,208,102,55,15,103,156,227,11,248,9,202,116,107,16,43,113,221,124,192,154,35,230,215,22,192,32,196,210,187,213]}}
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,7 @@ export class IndexPatternsService {
fieldFormatMap,
typeMeta,
type,
dataSourceId,
},
} = savedObject;

Expand All @@ -373,6 +374,7 @@ export class IndexPatternsService {
fields: this.fieldArrayToMap(parsedFields),
typeMeta: parsedTypeMeta,
type,
dataSourceId,
};
};

Expand Down
1 change: 1 addition & 0 deletions src/plugins/data/common/index_patterns/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ export interface IndexPatternAttributes {
intervalName?: string;
sourceFilters?: string;
fieldFormatMap?: string;
dataSourceId?: string;
}

export type OnNotification = (toastInputFields: ToastInputFields) => void;
Expand Down
1 change: 1 addition & 0 deletions src/plugins/data/common/search/opensearch_search/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ export type ISearchRequestParams<T = Record<string, any>> = {
export interface IOpenSearchSearchRequest
extends IOpenSearchDashboardsSearchRequest<ISearchRequestParams> {
indexType?: string;
dataSourceId?: string;
}

export type IOpenSearchSearchResponse<Source = any> = IOpenSearchDashboardsSearchResponse<
Expand Down
13 changes: 5 additions & 8 deletions src/plugins/data/common/search/search_source/search_source.ts
Original file line number Diff line number Diff line change
Expand Up @@ -289,10 +289,7 @@ export class SearchSource {
response = await this.legacyFetch(searchRequest, options);
} else {
if (this.dataSourceId) {
options = {
...options,
dataSourceId: this.dataSourceId,
};
searchRequest.dataSourceId = this.dataSourceId;
}
response = await this.fetchSearch(searchRequest, options);
}
Expand Down Expand Up @@ -346,10 +343,10 @@ export class SearchSource {
const params = getSearchParamsFromRequest(searchRequest, {
getConfig,
});

return search({ params, indexType: searchRequest.indexType }, options).then(({ rawResponse }) =>
onResponse(searchRequest, rawResponse)
);
return search(
{ params, indexType: searchRequest.indexType, dataSourceId: searchRequest.dataSourceId },
options
).then(({ rawResponse }) => onResponse(searchRequest, rawResponse));
}

/**
Expand Down
1 change: 1 addition & 0 deletions src/plugins/data/server/saved_objects/index_patterns.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ export const indexPatternSavedObjectType: SavedObjectsType = {
properties: {
title: { type: 'text' },
type: { type: 'keyword' },
dataSourceId: { type: 'keyword' },
},
},
migrations: indexPatternSavedObjectTypeMigrations as any,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,8 @@ export const opensearchSearchStrategyProvider = (
});

try {
const selectedClient = options?.dataSourceId
? await context.core.opensearchData.getClient(options?.dataSourceId)
const selectedClient = request.dataSourceId
? await context.core.opensearchData.getClient(request.dataSourceId)
: context.core.opensearch.client.asCurrentUser;

const promise = shimAbortSignal(selectedClient.search(params), options?.abortSignal);
Expand Down

0 comments on commit 1a8e74b

Please sign in to comment.