cancel
Showing results for 
Search instead for 
Did you mean: 
cancel
819
Views
1
Helpful
2
Replies

Error while trying to use preprocessing script in postman

Apoorva_Anne
Level 1
Level 1

I am using the below script in preprocessing step in POSTMAN but it is throwing an error

code": 40103,
“message”: “Invalid signature in request credentials”,
“stat”: “FAIL”

“PRE PROCESSING SCRIPT”

function getAuthHeader(httpMethod, requestUrl, requestBody) { console.log(requestBody); //body data console.log(httpMethod); // http type: POST, GET, ETC
var CLIENT_KEY = ‘xxxxxxx’;
var SECRET_KEY = ‘xxxxxxx’;
//var AUTH_TYPE = ‘HMAC-SHA1’;
var moment = require(‘moment’)
//const moment= require(‘moment’);
/* Uncomment out lines below to use your test for getting correct formatted time and date */
var timestamp = moment().format(‘ddd, DD MMM YYYY HH:mm:ss ZZ’);
//var timestamp1 = moment().utcOffset(‘timestamp’);
//var timestamp1 = timestamp.toUTCString();
pm.environment.set(“timestampHeader”,timestamp);
//var timestamp = “Mon, 24 Apr 2023 16:38:18 -0600” ;
//pm.environment.set(“timestampHeader”,timestamp);
var hostname = “■■■■■■■■■■■■■■■■■■■■■■■■”;
var apicall = ‘/admin/v1/users’
var method = ‘POST’
var body = ‘username=xxxx’ //sample username
var requestData = timestamp +‘\n’+method+‘\n’+ hostname +‘\n’+ apicall +‘\n’+ body;
//requestData = requestData.normalize([‘NFC’]);
console.log(requestData);
var hmacDigest = CryptoJS.HmacSHA1(requestData, SECRET_KEY);
console.log(hmacDigest);

var prebase = CLIENT_KEY+“:”+hmacDigest;
console.log(prebase);
var baseComplete = btoa(prebase);
console.log(baseComplete);
var authHeader = "Basic "+baseComplete;
return authHeader;
}
postman.setEnvironmentVariable(‘hmacAuthHeader’, getAuthHeader(request[‘method’], request[‘url’], request[‘data’]));

Headers :

I have seen few similar posts on this script, but no one is clear on how they made it working.

So can someone help on what I am missing in the script and to convert time to UTC?

1 Accepted Solution

Accepted Solutions

DuoPablo
Cisco Employee
Cisco Employee

Hi @Apoorva_Anne ,

You might have already seen this lengthy thread regarding the topic: Preauth API failing but check and ping are good - #14 by testdemo_user

I will paste the pre-request script that I have been using successfully (taken from the above thread). You should only need to replace the ikey, skey and API hostname. Keep the Headers that you already have.


//Tested on Postman for Web Version 10.13.6
 
function getAuthHeader(httpMethod, requestUrl, requestBody) {
    console.log(requestUrl); // Full URL
    console.log(httpMethod); // http type: POST, GET, ETC
    console.log(requestBody); //POST Body, currently not used
     
    var IKEY = '<ikey>'; //Auth or Admin API IKEY
    var SKEY = '<skey>'; //Auth or Admin API SKEY
    var API_HOSTNAME = '<api-hostname>'; //Auth or Admin API Hostname
    var AUTH_TYPE = 'HMAC-SHA1';
     
    //Adds a ? at the end of the URL even if there aren't any parameters, makes it easier to find the end of the api_call
    if (requestUrl.indexOf("?") == -1) {
        requestUrl += "?";
    }
     
    var paramsStart = requestUrl.indexOf("?");
    var hostname_length = API_HOSTNAME.length + 8;                  //api_hostname + https://
    var api_call = requestUrl.slice(hostname_length, paramsStart);  //remove hostname and params to get the api_call
    console.log(api_call);
     
    var params_unsorted = "";
    var params_array = [];
    //Create unsorted array of parameters from either URL or Body
    //Assuming POST parameters are in the Body, GET paramters are in URL
    //(technically it looks like POST can be in the URL as well)
 
    if (Object.keys(requestBody).length !== 0) {
        for (var parameter1 in requestBody) {
            params_unsorted = parameter1 + "=" + requestBody[parameter1];
            params_array.push(params_unsorted);
        }
    } else {
        params_unsorted = requestUrl.substring(paramsStart+1);
        params_array = params_unsorted.split("&");
    }
    console.log(params_array);
     
    params_array.sort();                    //lexicographically sort parameters by key
    var encoded_params = "";               
    if (params_array[0] !== ""){            //check if there are any Params to encode and create the string from
        var encoded_params_array = params_array.map(urlEncodeParams);   //create URL-encoded array of key=value pairs from the sorted array
        encoded_params = encoded_params_array.join("&");                //create string of parameters joined by &
    }
    console.log(encoded_params);
     
    //The current time, formatted as RFC 2822. This must be the same string as the "Date" header (or X-Duo-Date header).
    var moment = require('moment');
    var timestamp = moment().format("ddd, DD MMM YYYY HH:mm:ss ZZ");
    pm.environment.set("timestampHeader",timestamp);
 
    //Then concatenate these components with (line feed) newlines
    var requestData =  timestamp+"\n"+httpMethod+"\n"+API_HOSTNAME+"\n"+api_call+"\n"+encoded_params;
    console.log(requestData);
 
    //compute the HMAC-SHA1 of this canonical representation, using your Duo application's secret key as the HMAC key
    var hmacDigest = CryptoJS.HmacSHA1(requestData, SKEY);
    console.log(hmacDigest);
     
    //Use HTTP Basic Authentication for the request, using your integration key as the username and the HMAC-SHA1 signature as the password.
    var prebase = IKEY+":"+ hmacDigest;
    console.log(prebase);
     
    //encodes a string in base-64
    var baseComplete = btoa(prebase);
    console.log(baseComplete);
 
    var authHeader = "Basic "+ baseComplete;
    return authHeader;
}
 
function urlEncodeParams(value, index, array) {
    //split the Key and Value at the first "=", URL-encode the Value, and rejoin them with an "="
    //If the separator in the split() is a regular expression that contains capturing parentheses (), matched results are included in the array
    return value.split(/=(.+)/)[0] + "=" + encodeURIComponent(value.split(/=(.+)/)[1]);
}
 
pm.environment.set("hmacAuthHeader", getAuthHeader(request.method, request.url, request.data));

You can then perform the GET or POST to the endpoint of your choice (which initially appears to be https://■■■■■■■■■■■■■■■■■■■■■■■■■■■■/admin/v1/users) in the request field:
2X_a_a294f05ac40c0d56ca238eade7348d819497c8f2.png

Hope this helps!

View solution in original post

2 Replies 2

DuoPablo
Cisco Employee
Cisco Employee

Hi @Apoorva_Anne ,

You might have already seen this lengthy thread regarding the topic: Preauth API failing but check and ping are good - #14 by testdemo_user

I will paste the pre-request script that I have been using successfully (taken from the above thread). You should only need to replace the ikey, skey and API hostname. Keep the Headers that you already have.


//Tested on Postman for Web Version 10.13.6
 
function getAuthHeader(httpMethod, requestUrl, requestBody) {
    console.log(requestUrl); // Full URL
    console.log(httpMethod); // http type: POST, GET, ETC
    console.log(requestBody); //POST Body, currently not used
     
    var IKEY = '<ikey>'; //Auth or Admin API IKEY
    var SKEY = '<skey>'; //Auth or Admin API SKEY
    var API_HOSTNAME = '<api-hostname>'; //Auth or Admin API Hostname
    var AUTH_TYPE = 'HMAC-SHA1';
     
    //Adds a ? at the end of the URL even if there aren't any parameters, makes it easier to find the end of the api_call
    if (requestUrl.indexOf("?") == -1) {
        requestUrl += "?";
    }
     
    var paramsStart = requestUrl.indexOf("?");
    var hostname_length = API_HOSTNAME.length + 8;                  //api_hostname + https://
    var api_call = requestUrl.slice(hostname_length, paramsStart);  //remove hostname and params to get the api_call
    console.log(api_call);
     
    var params_unsorted = "";
    var params_array = [];
    //Create unsorted array of parameters from either URL or Body
    //Assuming POST parameters are in the Body, GET paramters are in URL
    //(technically it looks like POST can be in the URL as well)
 
    if (Object.keys(requestBody).length !== 0) {
        for (var parameter1 in requestBody) {
            params_unsorted = parameter1 + "=" + requestBody[parameter1];
            params_array.push(params_unsorted);
        }
    } else {
        params_unsorted = requestUrl.substring(paramsStart+1);
        params_array = params_unsorted.split("&");
    }
    console.log(params_array);
     
    params_array.sort();                    //lexicographically sort parameters by key
    var encoded_params = "";               
    if (params_array[0] !== ""){            //check if there are any Params to encode and create the string from
        var encoded_params_array = params_array.map(urlEncodeParams);   //create URL-encoded array of key=value pairs from the sorted array
        encoded_params = encoded_params_array.join("&");                //create string of parameters joined by &
    }
    console.log(encoded_params);
     
    //The current time, formatted as RFC 2822. This must be the same string as the "Date" header (or X-Duo-Date header).
    var moment = require('moment');
    var timestamp = moment().format("ddd, DD MMM YYYY HH:mm:ss ZZ");
    pm.environment.set("timestampHeader",timestamp);
 
    //Then concatenate these components with (line feed) newlines
    var requestData =  timestamp+"\n"+httpMethod+"\n"+API_HOSTNAME+"\n"+api_call+"\n"+encoded_params;
    console.log(requestData);
 
    //compute the HMAC-SHA1 of this canonical representation, using your Duo application's secret key as the HMAC key
    var hmacDigest = CryptoJS.HmacSHA1(requestData, SKEY);
    console.log(hmacDigest);
     
    //Use HTTP Basic Authentication for the request, using your integration key as the username and the HMAC-SHA1 signature as the password.
    var prebase = IKEY+":"+ hmacDigest;
    console.log(prebase);
     
    //encodes a string in base-64
    var baseComplete = btoa(prebase);
    console.log(baseComplete);
 
    var authHeader = "Basic "+ baseComplete;
    return authHeader;
}
 
function urlEncodeParams(value, index, array) {
    //split the Key and Value at the first "=", URL-encode the Value, and rejoin them with an "="
    //If the separator in the split() is a regular expression that contains capturing parentheses (), matched results are included in the array
    return value.split(/=(.+)/)[0] + "=" + encodeURIComponent(value.split(/=(.+)/)[1]);
}
 
pm.environment.set("hmacAuthHeader", getAuthHeader(request.method, request.url, request.data));

You can then perform the GET or POST to the endpoint of your choice (which initially appears to be https://■■■■■■■■■■■■■■■■■■■■■■■■■■■■/admin/v1/users) in the request field:
2X_a_a294f05ac40c0d56ca238eade7348d819497c8f2.png

Hope this helps!

Hey thanks for the script, Now it worked for me in postman.

Getting Started

Find answers to your questions by entering keywords or phrases in the Search bar above. New here? Use these resources to familiarize yourself with the community:

Quick Links