0 votes
1 view
in AWS by (18.2k points)

I'm trying to post data to Elasticsearch managed by AWS using AWS4 signing method. I would like to achieve this via postman pre-script. I tried using below script which worked perfectly for GET operation of Elastic search but it's not working for POST or PUT or DELETE operation & keep giving me an error message that the signature does not match for POST operation. Can someone help me in fixing below pre-script in postman?

var date = new Date().toISOString();

var amzdate = date.replace(/[:\-]|\.\d{3}/g, "");

var dateStamp = amzdate.slice(0, -8);

pm.environment.set('authorization', getAuthHeader(request.method, request.url, request.data));

pm.environment.set('xAmzDate', amzdate);

function getPath(url) {

    var pathRegex = /.+?\:\/\/.+?(\/.+?)(?:#|\?|$)/;

    var result = url.match(pathRegex);

    return result && result.length > 1 ? result[1] : '';

}

function getQueryString(url) {

    var arrSplit = url.split('?');

    return arrSplit.length > 1 ? url.substring(url.indexOf('?') + 1) : '';

}

function getSignatureKey(secretKey, dateStamp, regionName, serviceName) {

    var kDate = sign("AWS4" + secretKey, dateStamp);

    var kRegion = sign(kDate, regionName);

    var kService = sign(kRegion, serviceName);

    var kSigning = sign(kService, "aws4_request");

    return kSigning;

}

function sign(key, message) {

    return CryptoJS.HmacSHA256(message, key);

}

function getAuthHeader(httpMethod, requestUrl, requestBody) {

    var ACCESS_KEY = pm.globals.get("access_key");

    var SECRET_KEY = pm.globals.get("secret_key");

    var REGION = 'us-east-1';

    var SERVICE = 'es';

    var ALGORITHM = 'AWS4-HMAC-SHA256';

    var canonicalUri = getPath(requestUrl);

    var canonicalQueryString = getQueryString(requestUrl);

    if (httpMethod == 'GET' || !requestBody) {

        requestBody = '';

    } else {

        requestBody = JSON.stringify(requestBody);

    }

    var hashedPayload = CryptoJS.enc.Hex.stringify(CryptoJS.SHA256(requestBody));

    var canonicalHeaders = 'host:' + pm.environment.get("ESHost") + '\n' + 'x-amz-date:' + amzdate + '\n';

    var signedHeaders = 'host;x-amz-date';

    var canonicalRequestData = [httpMethod, canonicalUri, canonicalQueryString, canonicalHeaders, signedHeaders, hashedPayload].join("\n");

    var hashedRequestData = CryptoJS.enc.Hex.stringify(CryptoJS.SHA256(canonicalRequestData));

    var credentialScope = dateStamp + '/' + REGION + '/' + SERVICE + '/' + 'aws4_request';

    var stringToSign = ALGORITHM + '\n' + amzdate + '\n' + credentialScope + '\n' + hashedRequestData;

    var signingKey = getSignatureKey(SECRET_KEY, dateStamp, REGION, SERVICE);

    var signature = CryptoJS.HmacSHA256(stringToSign, signingKey).toString(CryptoJS.enc.Hex);

    var authHeader = ALGORITHM + ' ' + 'Credential=' + ACCESS_KEY + '/' + credentialScope + ', ' + 'SignedHeaders=' + signedHeaders + ', ' + 'Signature=' + signature;

    return authHeader;

}

1 Answer

0 votes
by (42.5k points)

There are a few bugs in the code, I will post them below with the corrected code:

  • getPath should return '/' when the path=' ' 
  • If request.data is empty body, then requestBody=' '
  • request.data provides JSON string as output, so no need for JSON.stringify(request.data)

Corrected code snippet: 

var date = new Date().toISOString();

var amzdate = date.replace(/[:\-]|\.\d{3}/g, "");

var dateStamp = amzdate.slice(0, -8);

pm.environment.set('authorization', getAuthHeader(request.method, request.url, request.data));

pm.environment.set('xAmzDate', amzdate);

function getPath(url) {

    var pathRegex = /.+?\:\/\/.+?(\/.+?)(?:#|\?|$)/;

    var result = url.match(pathRegex);

    return result && result.length > 1 ? result[1] : '/';

}

function getQueryString(url) {

    var arrSplit = url.split('?');

    return arrSplit.length > 1 ? url.substring(url.indexOf('?') + 1) : '';

}

function getSignatureKey(secretKey, dateStamp, regionName, serviceName) {

    var kDate = sign("AWS4" + secretKey, dateStamp);

    var kRegion = sign(kDate, regionName);

    var kService = sign(kRegion, serviceName);

    var kSigning = sign(kService, "aws4_request");

    return kSigning;

}

function sign(key, message) {

    return CryptoJS.HmacSHA256(message, key);

}

function getAuthHeader(httpMethod, requestUrl, requestBody) {

    var ACCESS_KEY = pm.globals.get("access_key");

    var SECRET_KEY = pm.globals.get("secret_key");

    var REGION = 'us-east-1';

    var SERVICE = 'es';

    var ALGORITHM = 'AWS4-HMAC-SHA256';

    var canonicalUri = getPath(requestUrl);

    var canonicalQueryString = getQueryString(requestUrl);


 

    if (httpMethod == 'GET' || !requestBody || Object.keys(requestBody).length === 0) {

        requestBody = '';

    } 

    var hashedPayload = CryptoJS.enc.Hex.stringify(CryptoJS.SHA256(requestBody));

    var canonicalHeaders = 'host:' + pm.environment.get("ESHost") + '\n' + 'x-amz-date:' + amzdate + '\n';

    var signedHeaders = 'host;x-amz-date';

    var canonicalRequestData = [httpMethod, canonicalUri, canonicalQueryString, canonicalHeaders, signedHeaders, hashedPayload].join("\n");

    var hashedRequestData = CryptoJS.enc.Hex.stringify(CryptoJS.SHA256(canonicalRequestData));

    var credentialScope = dateStamp + '/' + REGION + '/' + SERVICE + '/' + 'aws4_request';

    var stringToSign = ALGORITHM + '\n' + amzdate + '\n' + credentialScope + '\n' + hashedRequestData;

    var signingKey = getSignatureKey(SECRET_KEY, dateStamp, REGION, SERVICE);

    var signature = CryptoJS.HmacSHA256(stringToSign, signingKey).toString(CryptoJS.enc.Hex);

    var authHeader = ALGORITHM + ' ' + 'Credential=' + ACCESS_KEY + '/' + credentialScope + ', ' + 'SignedHeaders=' + signedHeaders + ', ' + 'Signature=' + signature;

    return authHeader;

}

Welcome to Intellipaat Community. Get your technical queries answered by top developers !


Categories

...