Skip to content

Commit

Permalink
Add max body support in edge grid auth (#1399)
Browse files Browse the repository at this point in the history
  • Loading branch information
sandeep-singh-pstmn committed Apr 8, 2024
1 parent 25c18bd commit 265ed7e
Show file tree
Hide file tree
Showing 5 changed files with 239 additions and 8 deletions.
40 changes: 34 additions & 6 deletions lib/authorizer/edgegrid.js
Original file line number Diff line number Diff line change
Expand Up @@ -88,15 +88,37 @@ var _ = require('lodash'),
return encrypt.digest('base64');
},

/**
* Trim the body if it exceeds the max body limit.
*
* @param {String|Buffer} body Request body
* @param {Number} size Maximum body size to hash
*/
limitRequestBody = function (body, size) {
if (!body || size <= 0) { return EMPTY; }

if (!Buffer.isBuffer(body)) {
// We are converting the body to a buffer to obtain the exact byte length and to precisely trim the body.
body = Buffer.from(body);
}

if (body.byteLength > size) {
body = body.subarray(0, size);
}

return body;
},

/**
* Calculates body hash with given algorithm and digestEncoding.
*
* @param {RequestBody} body Request body
* @param {String} algorithm Hash algorithm to use
* @param {String} digestEncoding Encoding of the hash
* @param {Number} maxBodySize Maximum body size to hash
* @param {Function} callback Callback function that will be called with body hash
*/
computeBodyHash = function (body, algorithm, digestEncoding, callback) {
computeBodyHash = function (body, algorithm, digestEncoding, maxBodySize, callback) {
if (!(body && algorithm && digestEncoding) || body.isEmpty()) { return callback(); }

var hash = crypto.createHash(algorithm),
Expand All @@ -107,15 +129,15 @@ var _ = require('lodash'),

if (body.mode === RequestBody.MODES.raw) {
rawBody = bodyBuilder.raw(body.raw).body;
hash.update(rawBody);
hash.update(limitRequestBody(rawBody, maxBodySize));

return callback(hash.digest(digestEncoding));
}

if (body.mode === RequestBody.MODES.urlencoded) {
urlencodedBody = bodyBuilder.urlencoded(body.urlencoded).form;
urlencodedBody = urlEncoder.encodeQueryString(urlencodedBody);
hash.update(urlencodedBody);
hash.update(limitRequestBody(urlencodedBody, maxBodySize));

return callback(hash.digest(digestEncoding));
}
Expand All @@ -129,9 +151,13 @@ var _ = require('lodash'),

return originalReadStream.cloneReadStream(function (err, clonedStream) {
if (err) { return callback(); }
let readBytes = 0;

clonedStream.on('data', function (chunk) {
hash.update(chunk);
if (readBytes <= maxBodySize) {
hash.update(limitRequestBody(chunk, maxBodySize - readBytes));
readBytes += chunk.byteLength;
}
});

clonedStream.on('end', function () {
Expand All @@ -142,7 +168,7 @@ var _ = require('lodash'),

if (body.mode === RequestBody.MODES.graphql) {
graphqlBody = bodyBuilder.graphql(body.graphql).body;
hash.update(graphqlBody);
hash.update(limitRequestBody(graphqlBody, maxBodySize));

return callback(hash.digest(digestEncoding));
}
Expand Down Expand Up @@ -257,6 +283,7 @@ module.exports = {
sign: function (auth, request, done) {
var params = auth.get([
'accessToken',
'maxBodySize',
'clientToken',
'clientSecret',
'baseURL',
Expand All @@ -279,6 +306,7 @@ module.exports = {
params.timestamp = params.timestamp || getTimestamp();
params.url = url;
params.method = request.method;
params.maxBodySize = params.maxBodySize || 131072; // 128 KB

// ensure that headers are case-insensitive as specified in the documentation
params.headers = request.getHeaders({ enabled: true, ignoreCase: true });
Expand All @@ -292,7 +320,7 @@ module.exports = {

// only calculate body hash for POST requests according to specification
if (request.method === 'POST') {
return computeBodyHash(request.body, 'sha256', 'base64', function (bodyHash) {
return computeBodyHash(request.body, 'sha256', 'base64', params.maxBodySize, function (bodyHash) {
params.bodyHash = bodyHash;

request.addHeader({
Expand Down
15 changes: 15 additions & 0 deletions test/fixtures/new.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
key, value
1, 😀
3, 4
5, 6
7, 8
9, 10
11, 12
13, 14
15, 16
17, 18
19, 20
21, 22
23, 24
25, 26
27, 28
3 changes: 2 additions & 1 deletion test/fixtures/servers/_servers.js
Original file line number Diff line number Diff line change
Expand Up @@ -384,6 +384,7 @@ function createEdgeGridAuthServer (options) {
accessToken: 'postman_access_token',
clientToken: 'postman_client_token',
clientSecret: 'postman_client_secret',
maxBodySize: 131072,
headersToSign: []
});

Expand Down Expand Up @@ -506,7 +507,7 @@ function createEdgeGridAuthServer (options) {
authParams.method = req.method;
authParams.path = req.url;
authParams.headers = req.headers;
authParams.body = body && body.toString && body.toString();
authParams.body = body && body.slice && body.subarray(0, options.maxBodySize);

requestSignature = calculateSignature(authParams);

Expand Down
3 changes: 2 additions & 1 deletion test/fixtures/servers/edgegrid.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ const server = require('./_servers'),
credentials = {
accessToken: 'postman_access_token',
clientToken: 'postman_client_token',
clientSecret: 'postman_client_secret'
clientSecret: 'postman_client_secret',
maxBodySize: 48
};

module.exports = server.createEdgeGridAuthServer(credentials);
186 changes: 186 additions & 0 deletions test/integration/auth-methods/edgegrid.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -374,4 +374,190 @@ describe('EdgeGrid auth', function () {
expect(response).to.have.property('code', 200);
});
});

describe('with correct credentials and max body, body as text', function () {
var testrun;

before(function (done) {
// perform the collection run
this.run({
collection: {
item: {
request: {
auth: {
type: 'edgegrid',
edgegrid: { ...credentials, maxBodySize: 48 }
},
url: global.servers.edgegrid,
method: 'POST',
body: {
mode: 'raw',
raw: 'Hello World!!! Hello World!!! Hello World!!! Hello World!!!'
}
}
}
}
}, function (err, results) {
testrun = results;
done(err);
});
});

it('should pass the EdgeGrid authentication', function () {
var response = testrun.request.getCall(0).args[2];

expect(response).to.have.property('code', 200);
});
});

describe('with correct credentials and max body, body as json', function () {
var testrun;

before(function (done) {
// perform the collection run
this.run({
collection: {
item: {
request: {
auth: {
type: 'edgegrid',
edgegrid: { ...credentials, maxBodySize: 48 }
},
url: global.servers.edgegrid,
method: 'POST',
body: {
mode: 'raw',
raw: '{\n "key": "Hello World!!! Hello World!!! Hello World!!! Hello World!!!"\n}',
options: {
raw: {
language: 'json'
}
}
}
}
}
}
}, function (err, results) {
testrun = results;
done(err);
});
});

it('should pass the EdgeGrid authentication', function () {
var response = testrun.request.getCall(0).args[2];

expect(response).to.have.property('code', 200);
});
});

describe('with correct credentials and max body, body as GraphQl', function () {
var testrun;

before(function (done) {
// perform the collection run
this.run({
collection: {
item: {
request: {
auth: {
type: 'edgegrid',
edgegrid: { ...credentials, maxBodySize: 48 }
},
url: global.servers.edgegrid,
method: 'POST',
body: {
mode: 'graphql',
graphql: {
query: 'query Hello {\n Hello World!!! Hello World!!! Hello World!!! Hello\n}',
variables: ''
}
}
}
}
}
}, function (err, results) {
testrun = results;
done(err);
});
});

it('should pass the EdgeGrid authentication', function () {
var response = testrun.request.getCall(0).args[2];

expect(response).to.have.property('code', 200);
});
});

describe('with correct credentials and max body, body as binary file', function () {
var testrun;

before(function (done) {
// perform the collection run
this.run({
collection: {
item: {
request: {
auth: {
type: 'edgegrid',
edgegrid: { ...credentials, maxBodySize: 48 }
},
url: global.servers.edgegrid,
method: 'POST',
body: {
mode: 'file',
file: {
src: path.resolve(__dirname, '../../fixtures/new.csv')
}
}
}
}
},
fileResolver: fs
}, function (err, results) {
testrun = results;
done(err);
});
});

it('should pass the EdgeGrid authentication', function () {
var response = testrun.request.getCall(0).args[2];

expect(response).to.have.property('code', 200);
});
});

describe('should fail when we have default max body but server has 48Bytes as max-body', function () {
var testrun;

before(function (done) {
// perform the collection run
this.run({
collection: {
item: {
request: {
auth: {
type: 'edgegrid',
edgegrid: { ...credentials }
},
url: global.servers.edgegrid,
method: 'POST',
body: {
mode: 'raw',
raw: 'Hello World!!! Hello World!!! Hello World!!! Hello World!!!'
}
}
}
}
}, function (err, results) {
testrun = results;
done(err);
});
});

it('should pass the EdgeGrid authentication', function () {
var response = testrun.request.getCall(0).args[2];

expect(response).to.have.property('code', 401);
});
});
});

0 comments on commit 265ed7e

Please sign in to comment.