From e47f7e4327af63793c97db88553ab21574aea303 Mon Sep 17 00:00:00 2001 From: Vincent Date: Sat, 1 Oct 2022 04:44:15 +0700 Subject: [PATCH] Feature/add default credentials provider (#295) * add default credentials provider to AwsSigv4Signer Signed-off-by: rawpixel-vincent * update default credentials function name Signed-off-by: rawpixel-vincent Signed-off-by: rawpixel-vincent --- lib/aws/AwsSigv4Signer.js | 46 +++++++++++++++++++++++- lib/aws/index.d.ts | 2 +- test/unit/lib/aws/awssigv4signer.test.js | 44 +++++++++++++++++------ 3 files changed, 80 insertions(+), 12 deletions(-) diff --git a/lib/aws/AwsSigv4Signer.js b/lib/aws/AwsSigv4Signer.js index 6ab50f545..d3253e139 100644 --- a/lib/aws/AwsSigv4Signer.js +++ b/lib/aws/AwsSigv4Signer.js @@ -14,6 +14,50 @@ const Transport = require('../Transport'); const aws4 = require('aws4'); const AwsSigv4SignerError = require('./errors'); +const getAwsSDKCredentialsProvider = async () => { + // First try V3 + try { + const awsV3 = await import('@aws-sdk/credential-provider-node'); + if (typeof awsV3.defaultProvider === 'function') { + return awsV3.defaultProvider(); + } + } catch (err) { + // Ignore + } + try { + const awsV2 = await import('aws-sdk'); + if (awsV2.default && typeof awsV2.default.config.getCredentials === 'function') { + return () => + new Promise((resolve, reject) => { + awsV2.default.config.getCredentials((err, credentials) => { + if (err) { + reject(err); + } else { + resolve(credentials); + } + }); + }); + } + } catch (err) { + // Ignore + } + + throw new AwsSigv4SignerError( + 'Unable to find a valid AWS SDK, please provide a valid getCredentials function to AwsSigv4Signer options.' + ); +}; + +const awsDefaultCredentialsProvider = () => + new Promise((resolve, reject) => { + getAwsSDKCredentialsProvider() + .then((provider) => { + provider().then(resolve).catch(reject); + }) + .catch((err) => { + reject(err); + }); + }); + function AwsSigv4Signer(opts) { const credentialsState = { credentials: null, @@ -22,7 +66,7 @@ function AwsSigv4Signer(opts) { throw new AwsSigv4SignerError('Region cannot be empty'); } if (opts && typeof opts.getCredentials !== 'function') { - throw new AwsSigv4SignerError('getCredentials function is required'); + opts.getCredentials = awsDefaultCredentialsProvider; } function buildSignedRequestObject(request = {}) { diff --git a/lib/aws/index.d.ts b/lib/aws/index.d.ts index 0f9f79592..a36b701c8 100644 --- a/lib/aws/index.d.ts +++ b/lib/aws/index.d.ts @@ -17,7 +17,7 @@ import * as http from 'http'; import { OpenSearchClientError } from '../errors'; interface AwsSigv4SignerOptions { - getCredentials: () => Promise; + getCredentials?: () => Promise; region: string; } diff --git a/test/unit/lib/aws/awssigv4signer.test.js b/test/unit/lib/aws/awssigv4signer.test.js index c0f5a3465..f1dfc084f 100644 --- a/test/unit/lib/aws/awssigv4signer.test.js +++ b/test/unit/lib/aws/awssigv4signer.test.js @@ -76,20 +76,44 @@ test('Sign with SigV4 failure (with empty region)', (t) => { } }); -test('Sign with SigV4 failure (without getCredentials function)', (t) => { +test('Sign with SigV4 using default getCredentials provider', (t) => { t.plan(2); - const mockRegion = 'us-west-2'; + function handler(req, res) { + res.setHeader('Content-Type', 'application/json;utf=8'); + res.end(JSON.stringify({ hello: 'world' })); + } - const AwsSigv4SignerOptions = { region: mockRegion }; + buildServer(handler, ({ port }, server) => { + const mockRegion = 'us-east-1'; - try { - AwsSigv4Signer(AwsSigv4SignerOptions); - t.fail('Should fail'); - } catch (err) { - t.ok(err instanceof AwsSigv4SignerError); - t.same(err.message, 'getCredentials function is required'); - } + const AwsSigv4SignerOptions = { + region: mockRegion, + }; + const client = new Client({ + ...AwsSigv4Signer(AwsSigv4SignerOptions), + node: `http://localhost:${port}`, + }); + + client + .search({ + index: 'test', + q: 'foo:bar', + }) + .then(() => { + t.fail('Should fail'); + }) + .catch((err) => { + t.ok(err instanceof AwsSigv4SignerError); + t.same( + err.message, + 'Unable to find a valid AWS SDK, please provide a valid getCredentials function to AwsSigv4Signer options.' + ); + }) + .finally(() => { + server.stop(); + }); + }); }); test('Basic aws (promises)', (t) => {