Skip to content

Commit be4a8cb

Browse files
wconti27watson
authored andcommitted
fix aws-sdk invalid signature exception (#5127)
Enables tracing header injection on AWS signed requests and fixes problem causing InvalidSignatureException.
1 parent 3b5a75d commit be4a8cb

File tree

2 files changed

+17
-162
lines changed

2 files changed

+17
-162
lines changed

packages/datadog-plugin-http/src/client.js

+5-33
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,11 @@ class HttpClientPlugin extends ClientPlugin {
5959
}
6060

6161
if (this.shouldInjectTraceHeaders(options, uri)) {
62+
// Clone the headers object in case an upstream lib has a reference to the original headers
63+
// Implemented due to aws-sdk issue where request signing is broken if we mutate the headers
64+
// Explained further in:
65+
// https://github.com/open-telemetry/opentelemetry-js-contrib/issues/1609#issuecomment-1826167348
66+
options.headers = Object.assign({}, options.headers)
6267
this.tracer.inject(span, HTTP_HEADERS, options.headers)
6368
}
6469

@@ -72,10 +77,6 @@ class HttpClientPlugin extends ClientPlugin {
7277
}
7378

7479
shouldInjectTraceHeaders (options, uri) {
75-
if (hasAmazonSignature(options) && !this.config.enablePropagationWithAmazonHeaders) {
76-
return false
77-
}
78-
7980
if (!this.config.propagationFilter(uri)) {
8081
return false
8182
}
@@ -212,31 +213,6 @@ function getHooks (config) {
212213
return { request }
213214
}
214215

215-
function hasAmazonSignature (options) {
216-
if (!options) {
217-
return false
218-
}
219-
220-
if (options.headers) {
221-
const headers = Object.keys(options.headers)
222-
.reduce((prev, next) => Object.assign(prev, {
223-
[next.toLowerCase()]: options.headers[next]
224-
}), {})
225-
226-
if (headers['x-amz-signature']) {
227-
return true
228-
}
229-
230-
if ([].concat(headers.authorization).some(startsWith('AWS4-HMAC-SHA256'))) {
231-
return true
232-
}
233-
}
234-
235-
const search = options.search || options.path
236-
237-
return search && search.toLowerCase().indexOf('x-amz-signature=') !== -1
238-
}
239-
240216
function extractSessionDetails (options) {
241217
if (typeof options === 'string') {
242218
return new URL(options).host
@@ -248,8 +224,4 @@ function extractSessionDetails (options) {
248224
return { host, port }
249225
}
250226

251-
function startsWith (searchString) {
252-
return value => String(value).startsWith(searchString)
253-
}
254-
255227
module.exports = HttpClientPlugin

packages/datadog-plugin-http/test/client.spec.js

+12-129
Original file line numberDiff line numberDiff line change
@@ -446,97 +446,24 @@ describe('Plugin', () => {
446446
})
447447
})
448448

449-
it('should skip injecting if the Authorization header contains an AWS signature', done => {
450-
const app = express()
451-
452-
app.get('/', (req, res) => {
453-
try {
454-
expect(req.get('x-datadog-trace-id')).to.be.undefined
455-
expect(req.get('x-datadog-parent-id')).to.be.undefined
456-
457-
res.status(200).send()
458-
459-
done()
460-
} catch (e) {
461-
done(e)
462-
}
463-
})
464-
465-
appListener = server(app, port => {
466-
const req = http.request({
467-
port,
468-
headers: {
469-
Authorization: 'AWS4-HMAC-SHA256 ...'
470-
}
471-
})
449+
it('should inject tracing header into request without mutating the header', done => {
450+
// ensures that the tracer clones request headers instead of mutating.
451+
// Fixes aws-sdk InvalidSignatureException, more info:
452+
// https://github.com/open-telemetry/opentelemetry-js-contrib/issues/1609#issuecomment-1826167348
472453

473-
req.end()
474-
})
475-
})
476-
477-
it('should skip injecting if one of the Authorization headers contains an AWS signature', done => {
478454
const app = express()
479455

480-
app.get('/', (req, res) => {
481-
try {
482-
expect(req.get('x-datadog-trace-id')).to.be.undefined
483-
expect(req.get('x-datadog-parent-id')).to.be.undefined
484-
485-
res.status(200).send()
486-
487-
done()
488-
} catch (e) {
489-
done(e)
490-
}
491-
})
492-
493-
appListener = server(app, port => {
494-
const req = http.request({
495-
port,
496-
headers: {
497-
Authorization: ['AWS4-HMAC-SHA256 ...']
498-
}
499-
})
500-
501-
req.end()
502-
})
503-
})
504-
505-
it('should skip injecting if the X-Amz-Signature header is set', done => {
506-
const app = express()
456+
const originalHeaders = {
457+
Authorization: 'AWS4-HMAC-SHA256 ...'
458+
}
507459

508460
app.get('/', (req, res) => {
509461
try {
510-
expect(req.get('x-datadog-trace-id')).to.be.undefined
511-
expect(req.get('x-datadog-parent-id')).to.be.undefined
512-
513-
res.status(200).send()
514-
515-
done()
516-
} catch (e) {
517-
done(e)
518-
}
519-
})
520-
521-
appListener = server(app, port => {
522-
const req = http.request({
523-
port,
524-
headers: {
525-
'X-Amz-Signature': 'abc123'
526-
}
527-
})
528-
529-
req.end()
530-
})
531-
})
532-
533-
it('should skip injecting if the X-Amz-Signature query param is set', done => {
534-
const app = express()
462+
expect(req.get('x-datadog-trace-id')).to.be.a('string')
463+
expect(req.get('x-datadog-parent-id')).to.be.a('string')
535464

536-
app.get('/', (req, res) => {
537-
try {
538-
expect(req.get('x-datadog-trace-id')).to.be.undefined
539-
expect(req.get('x-datadog-parent-id')).to.be.undefined
465+
expect(originalHeaders['x-datadog-trace-id']).to.be.undefined
466+
expect(originalHeaders['x-datadog-parent-id']).to.be.undefined
540467

541468
res.status(200).send()
542469

@@ -549,7 +476,7 @@ describe('Plugin', () => {
549476
appListener = server(app, port => {
550477
const req = http.request({
551478
port,
552-
path: '/?X-Amz-Signature=abc123'
479+
headers: originalHeaders
553480
})
554481

555482
req.end()
@@ -1093,50 +1020,6 @@ describe('Plugin', () => {
10931020
})
10941021
})
10951022

1096-
describe('with config enablePropagationWithAmazonHeaders enabled', () => {
1097-
let config
1098-
1099-
beforeEach(() => {
1100-
config = {
1101-
enablePropagationWithAmazonHeaders: true
1102-
}
1103-
1104-
return agent.load('http', config)
1105-
.then(() => {
1106-
http = require(pluginToBeLoaded)
1107-
express = require('express')
1108-
})
1109-
})
1110-
1111-
it('should inject tracing header into AWS signed request', done => {
1112-
const app = express()
1113-
1114-
app.get('/', (req, res) => {
1115-
try {
1116-
expect(req.get('x-datadog-trace-id')).to.be.a('string')
1117-
expect(req.get('x-datadog-parent-id')).to.be.a('string')
1118-
1119-
res.status(200).send()
1120-
1121-
done()
1122-
} catch (e) {
1123-
done(e)
1124-
}
1125-
})
1126-
1127-
appListener = server(app, port => {
1128-
const req = http.request({
1129-
port,
1130-
headers: {
1131-
Authorization: 'AWS4-HMAC-SHA256 ...'
1132-
}
1133-
})
1134-
1135-
req.end()
1136-
})
1137-
})
1138-
})
1139-
11401023
describe('with validateStatus configuration', () => {
11411024
let config
11421025

0 commit comments

Comments
 (0)