From 1a9906dadb5979794f215eae458ee34e79340cf6 Mon Sep 17 00:00:00 2001 From: dblock Date: Thu, 8 Aug 2024 12:40:27 -0400 Subject: [PATCH] Refactored auth and made logger required. Signed-off-by: dblock --- tests/default/cat/plugins.yaml | 2 - tools/src/OpenSearchHttpClient.ts | 82 ++++++++++--------- .../tests/tester/OpenSearchHttpClient.test.ts | 18 ++-- tools/tests/tester/helpers.ts | 6 +- 4 files changed, 59 insertions(+), 49 deletions(-) diff --git a/tests/default/cat/plugins.yaml b/tests/default/cat/plugins.yaml index 383576a7b..a2fb2b42f 100644 --- a/tests/default/cat/plugins.yaml +++ b/tests/default/cat/plugins.yaml @@ -9,5 +9,3 @@ chapters: format: json response: status: 200 - payload: - - component: opensearch-alerting diff --git a/tools/src/OpenSearchHttpClient.ts b/tools/src/OpenSearchHttpClient.ts index 6ef95f0f4..f81656074 100644 --- a/tools/src/OpenSearchHttpClient.ts +++ b/tools/src/OpenSearchHttpClient.ts @@ -11,8 +11,8 @@ import { Option } from '@commander-js/extra-typings' import axios, { type AxiosInstance, type AxiosRequestConfig, type AxiosResponse, type ResponseType } from 'axios' import * as https from 'node:https' import { sleep } from './helpers' -import { Logger } from 'Logger' -import { aws4Interceptor } from "aws4-axios" +import { Logger } from './Logger' +import { aws4Interceptor } from 'aws4-axios' const DEFAULT_URL = 'https://localhost:9200' const DEFAULT_USER = 'admin' @@ -49,18 +49,26 @@ export const AWS_SERVICE_OPTION = new Option('--aws-service ', 'AWS ser .env('AWS_SERVICE') .default('es') -export interface OpenSearchHttpClientOptions { - url?: string - username?: string - password?: string - insecure?: boolean - aws_access_key_id?: string - aws_access_secret_key?: string +export interface BasicAuth { + username: string + password: string +} + +export interface AwsAuth { + aws_access_key_id: string + aws_access_secret_key: string aws_access_session_token?: string aws_region?: string aws_service?: string +} + +export interface OpenSearchHttpClientOptions { + url?: string + insecure?: boolean responseType?: ResponseType - logger?: Logger + logger?: Logger, + basic_auth?: BasicAuth + aws_auth?: AwsAuth } export type OpenSearchHttpClientCliOptions = { @@ -80,14 +88,18 @@ export type OpenSearchHttpClientCliOptions = { export function get_opensearch_opts_from_cli (opts: OpenSearchHttpClientCliOptions): OpenSearchHttpClientOptions { return { url: opts.opensearchUrl, - username: opts.opensearchUsername, - password: opts.opensearchPassword, insecure: opts.opensearchInsecure, - aws_access_key_id: opts?.awsAccessKeyId, - aws_access_secret_key: opts?.awsSecretAccessKey, - aws_access_session_token: opts?.awsSessionToken, - aws_region: opts?.awsRegion, - aws_service: opts?.awsService, + basic_auth: opts.opensearchUsername !== undefined && opts.opensearchPassword !== undefined ? { + username: opts.opensearchUsername, + password: opts.opensearchPassword + } : undefined, + aws_auth: opts.awsAccessKeyId !== undefined && opts.awsSecretAccessKey !== undefined ? { + aws_access_key_id: opts?.awsAccessKeyId, + aws_access_secret_key: opts?.awsSecretAccessKey, + aws_access_session_token: opts?.awsSessionToken, + aws_region: opts?.awsRegion, + aws_service: opts?.awsService, + } : undefined, responseType: opts.responseType, logger: opts?.logger } @@ -115,39 +127,33 @@ export interface OpenSearchInfo { export class OpenSearchHttpClient { private readonly _axios: AxiosInstance private readonly _opts?: OpenSearchHttpClientOptions - private readonly _logger?: Logger + private readonly _logger: Logger constructor (opts?: OpenSearchHttpClientOptions) { this._opts = opts - this._logger = opts?.logger + this._logger = opts?.logger ?? new Logger() let auth = undefined let sigv4_interceptor = undefined - if (opts?.username !== undefined && opts.password !== undefined) { - this._logger?.info(`Authenticating with ${opts.username} ...`) - auth = { - username: opts.username, - password: opts.password - } - } else if ( - opts?.aws_access_key_id !== undefined && - opts?.aws_access_secret_key !== undefined - ) { - this._logger?.info(`Authenticating using SigV4 with ${opts.aws_access_key_id} (${opts.aws_region}) ...`) + if (opts?.basic_auth !== undefined) { + this._logger.info(`Authenticating with ${opts.basic_auth.username} ...`) + auth = opts.basic_auth + } else if (opts?.aws_auth !== undefined) { + this._logger.info(`Authenticating using SigV4 with ${opts.aws_auth.aws_access_key_id} (${opts.aws_auth.aws_region}) ...`) sigv4_interceptor = aws4Interceptor({ options: { - region: opts.aws_region, + region: opts.aws_auth.aws_region, service: 'es' }, credentials: { - accessKeyId: opts.aws_access_key_id, - secretAccessKey: opts.aws_access_secret_key, - sessionToken: opts.aws_access_session_token, + accessKeyId: opts.aws_auth.aws_access_key_id, + secretAccessKey: opts.aws_auth.aws_access_secret_key, + sessionToken: opts.aws_auth.aws_access_session_token, } }); } else { - this._logger?.warn(`No credentials provided, did you forget to set OPENSEARCH_PASSWORD or AWS_ACCESS_KEY_ID?`) + this._logger.warn(`No credentials provided, did you forget to set OPENSEARCH_PASSWORD or AWS_ACCESS_KEY_ID?`) } this._axios = axios.create({ @@ -166,7 +172,7 @@ export class OpenSearchHttpClient { let attempt = 0 while (true) { attempt += 1 - this._logger?.info(`Connecting to ${this._opts?.url} ... (${attempt}/${max_attempts})`) + this._logger.info(`Connecting to ${this._opts?.url} ... (${attempt}/${max_attempts})`) try { const info = await this.get('/') if (this._opts?.responseType == 'arraybuffer') { @@ -176,14 +182,14 @@ export class OpenSearchHttpClient { } } catch (e) { if (axios.isAxiosError(e)) { - this._logger?.warn(`Error connecting to ${this._opts?.url}: (${e.message})`) + this._logger.warn(`Error connecting to ${this._opts?.url}: (${e.message})`) if (e.response?.status == 401 || e.code === 'UNABLE_TO_VERIFY_LEAF_SIGNATURE') { throw e.message } else if (e.response?.status == 403 || e.code === 'ERR_BAD_REQUEST') { throw e.message } } else { - this._logger?.warn(`Error connecting to ${this._opts?.url}: (${typeof (e)})`) + this._logger.warn(`Error connecting to ${this._opts?.url}: (${typeof (e)})`) } if (attempt >= max_attempts) { throw e diff --git a/tools/tests/tester/OpenSearchHttpClient.test.ts b/tools/tests/tester/OpenSearchHttpClient.test.ts index 14c9a22b1..e2687e7fd 100644 --- a/tools/tests/tester/OpenSearchHttpClient.test.ts +++ b/tools/tests/tester/OpenSearchHttpClient.test.ts @@ -27,8 +27,10 @@ describe('OpenSearchHttpClient', () => { it('uses password authentication', () => { new OpenSearchHttpClient({ url: 'https://localhost:9200', - username: 'admin', - password: 'password' + basic_auth: { + username: 'admin', + password: 'password' + } }) expect(mocked_axios.create.mock.calls[0][0]).toMatchObject({ @@ -45,11 +47,13 @@ describe('OpenSearchHttpClient', () => { it('assigns a request interceptor with SigV4 authentication', () => { new OpenSearchHttpClient({ url: 'https://localhost:9200', - aws_access_key_id: 'key id', - aws_access_secret_key: 'secret key', - aws_access_session_token: 'session token', - aws_region: 'us-west-2', - aws_service: 'aoss' + aws_auth: { + aws_access_key_id: 'key id', + aws_access_secret_key: 'secret key', + aws_access_session_token: 'session token', + aws_region: 'us-west-2', + aws_service: 'aoss' + } }) expect(mocked_axios.create.mock.calls[0][0]).toMatchObject({ diff --git a/tools/tests/tester/helpers.ts b/tools/tests/tester/helpers.ts index dd6758d2a..9e4cf2d46 100644 --- a/tools/tests/tester/helpers.ts +++ b/tools/tests/tester/helpers.ts @@ -41,8 +41,10 @@ export function construct_tester_components (spec_path: string): { const operation_locator = new OperationLocator(specification) const opensearch_http_client = new OpenSearchHttpClient({ insecure: true, - username: process.env.OPENSEARCH_USERNAME ?? 'admin', - password: process.env.OPENSEARCH_PASSWORD ?? 'myStrongPassword123!', + basic_auth: { + username: process.env.OPENSEARCH_USERNAME ?? 'admin', + password: process.env.OPENSEARCH_PASSWORD ?? 'myStrongPassword123!' + }, responseType: 'arraybuffer' }) const chapter_reader = new ChapterReader(opensearch_http_client, logger)