Skip to content

Commit

Permalink
Backport/backport 333 to 1.x (opensearch-project#398)
Browse files Browse the repository at this point in the history
* Backport opensearch-project#333 into 1.x

Signed-off-by: Harsha Vamsi Kalluri <[email protected]>

* Remove un-necessary tests

Signed-off-by: Harsha Vamsi Kalluri <[email protected]>

---------

Signed-off-by: Harsha Vamsi Kalluri <[email protected]>
  • Loading branch information
harshavamsi authored Feb 21, 2023
1 parent aa64b9e commit 8156473
Show file tree
Hide file tree
Showing 2 changed files with 96 additions and 25 deletions.
57 changes: 52 additions & 5 deletions lib/aws/AwsSigv4Signer.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,19 +15,66 @@ const Transport = require('../Transport')
const aws4 = require('aws4')
const AwsSigv4SignerError = require('./errors')

function AwsSigv4Signer (opts) {
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
}
if (opts && (!opts.region || opts.region === null || opts.region === '')) {
if (!opts.region) {
throw new AwsSigv4SignerError('Region cannot be empty')
}
if (opts && typeof opts.getCredentials !== 'function') {
throw new AwsSigv4SignerError('getCredentials function is required')
if (!opts.service) {
opts.service = 'es'
}
if (typeof opts.getCredentials !== 'function') {
opts.getCredentials = awsDefaultCredentialsProvider
}

function buildSignedRequestObject (request = {}) {
request.service = 'es'
request.service = opts.service
request.region = opts.region
request.headers = request.headers || {}
request.headers.host = request.hostname
Expand Down
64 changes: 44 additions & 20 deletions test/unit/lib/aws/awssigv4signer.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ const { Connection } = require('../../../../index')
const { Client, buildServer } = require('../../../utils')

test('Sign with SigV4', (t) => {
t.plan(2)
t.plan(3)

const mockCreds = {
accessKeyId: uuidv4(),
Expand Down Expand Up @@ -51,46 +51,70 @@ test('Sign with SigV4', (t) => {
const signedRequest = auth.buildSignedRequestObject(request)
t.hasProp(signedRequest.headers, 'X-Amz-Date')
t.hasProp(signedRequest.headers, 'Authorization')
t.same(signedRequest.service, 'es')
})

test('Sign with SigV4 failure (with empty region)', (t) => {
t.plan(2)

const mockCreds = {
accessKeyId: uuidv4(),
secretAccessKey: uuidv4()
}

const mockRegions = [{ region: undefined }, { region: null }, { region: '' }, {}]

const AwsSigv4SignerOptions = {
getCredentials: () =>
new Promise((resolve) => {
setTimeout(() => resolve(mockCreds), 100)
})
}

try {
AwsSigv4Signer(AwsSigv4SignerOptions)
t.fail('Should fail')
} catch (err) {
t.ok(err instanceof AwsSigv4SignerError)
t.same(err.message, 'Region cannot be empty')
}
mockRegions.forEach((region) => {
try {
AwsSigv4Signer(Object.assign({}, AwsSigv4SignerOptions, region))
t.fail('Should fail')
} catch (err) {
t.ok(err instanceof AwsSigv4SignerError)
t.same(err.message, 'Region cannot be empty')
}
})

t.end()
})

test('Sign with SigV4 failure (without getCredentials function)', (t) => {
t.plan(2)
test('Sign with SigV4 and provided service', (t) => {
t.plan(1)

const mockRegion = 'us-west-2'
const mockCreds = {
accessKeyId: uuidv4(),
secretAccessKey: uuidv4()
}

const AwsSigv4SignerOptions = { region: mockRegion }
const mockRegion = 'us-west-2'
const mockService = 'foo'

try {
AwsSigv4Signer(AwsSigv4SignerOptions)
t.fail('Should fail')
} catch (err) {
t.ok(err instanceof AwsSigv4SignerError)
t.same(err.message, 'getCredentials function is required')
const AwsSigv4SignerOptions = {
getCredentials: () =>
new Promise((resolve) => {
setTimeout(() => resolve(mockCreds), 100)
}),
region: mockRegion,
service: mockService
}

const auth = AwsSigv4Signer(AwsSigv4SignerOptions)

const connection = new Connection({
url: new URL('https://localhost:9200')
})

const request = connection.buildRequestObject({
path: '/hello',
method: 'GET'
})

const signedRequest = auth.buildSignedRequestObject(request)
t.same(signedRequest.service, mockService)
})

test('Basic aws (promises)', (t) => {
Expand Down

0 comments on commit 8156473

Please sign in to comment.