cancel
Showing results for 
Search instead for 
Did you mean: 
cancel
828
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.

Quick Links