Need some assistance with CyberSource authentication please - cybersource

I am trying to post a request for "flex/v1/keys" api and i am trying to mirror the examples CyberSource have on the api page. But i keep getting back {"response":{"rmsg":"Authentication Failed"}} .
Please can someone assist me i am clueless and been struggling for a while now.
Code for getting headers sorted.
var crypto = require("crypto-js");
var requestHost = 'apitest.cybersource.com';
var merchantId = 'testrest';
var merchantKeyId = '08c94330-f618-42a3-b09d-e1e43be5efda';
var merchantSecretKey = 'yBJxy6LjM2TmcPGu+GaJrHtkke25fPpUX+UY6/L/1tE=';
var resource = "/flex/v1/keys";
//digest
var payload = '{"encryptionType": "None"}';
var data = crypto.enc.Utf8.parse(payload)
var hash = crypto.SHA256(data)
var base64 = crypto.enc.Base64.stringify(hash);
var digest = "SHA-256=" + base64;
pm.globals.set("digest",digest);
//date
var date = new Date(Date.now()).toUTCString();
pm.globals.set("date",date);
//signature
var signatureHeader = "";
signatureHeader += "keyid=\"" + merchantKeyId + "\"";
signatureHeader += ", algorithm=\"HmacSHA256\"";
var headersForPostMethod = "host date (request-target) digest v-c-merchant-id";
signatureHeader += ", headers=\"" + headersForPostMethod + "\"";
var signatureString = 'host: ' + requestHost;
signatureString += '\ndate: ' + new Date(Date.now()).toUTCString();
signatureString += '\n(request-target): ';
var targetUrlForPost = "post " + resource;
signatureString += targetUrlForPost + '\n';
signatureString += 'digest: SHA-256=' + digest + '\n';
signatureString += 'v-c-merchant-id: ' + merchantId;
var dataSigString = crypto.enc.Utf8.parse(signatureString);
var secKey = crypto.enc.Base64.parse(merchantSecretKey);
var hashHmac = CryptoJS.HmacSHA256(dataSigString, secKey)
var base64hashHmac = CryptoJS.enc.Base64.stringify(hashHmac);
signatureHeader += ", signature=\"" + base64hashHmac + "\"";
pm.globals.set("signature",signatureHeader);
My post request i am trying to send.
curl --location --request POST 'https://apitest.cybersource.com/flex/v1/keys' \
--header 'digest: SHA-256=yF79QR9XHmXEMjhnXRIvsaGie/xoTduWMP8kMOUIyVc=' \
--header 'v-c-merchant-id: testrest' \
--header 'date: Fri, 29 May 2020 15:06:42 GMT' \
--header 'host: apitest.cybersource.com' \
--header 'signature: keyid="08c94330-f618-42a3-b09d-e1e43be5efda", algorithm="HmacSHA256", headers="host date (request-target) digest v-c-merchant-id", signature="lnv5/zeUimcef0Dr3VeOyKgOw/cX8Erdb+qaKuSwuug="' \
--header 'profile-id: 93B32398-AD51-4CC2-A682-EA3E93614EB1' \
--header 'Content-Type: application/json' \
--data-raw '{"encryptionType": "None"}'
RESULTS
POST https://apitest.cybersource.com/flex/v1/keys
Request Headers
digest: SHA-256=yF79QR9XHmXEMjhnXRIvsaGie/xoTduWMP8kMOUIyVc=
v-c-merchant-id: testrest
date: Fri, 29 May 2020 14:57:17 GMT
host: apitest.cybersource.com
signature: keyid="08c94330-f618-42a3-b09d-e1e43be5efda", algorithm="HmacSHA256", headers="host date (request-target) digest v-c-merchant-id", signature="cLFxiYvra8KMBOaTB25Ke+gnQh67/MMn9wr0d8PRSm4="
profile-id: 93B32398-AD51-4CC2-A682-EA3E93614EB1
Content-Type: application/json
User-Agent: PostmanRuntime/7.25.0
Accept: */*
Cache-Control: no-cache
Postman-Token: ef33044d-e745-4014-bdd8-d30f659be760
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
Content-Length: 27
Request Body
{"encryptionType": "None"}↵
Response Headers
Strict-Transport-Security: max-age=31536000
v-c-correlation-id: 9e9d8293-b909-4fdf-9ae6-9f992e5dca87
content-type: application/json
v-c-response-time: 1590764238
content-length: 45
Response Body
{"response":{"rmsg":"Authentication Failed"}}

for anyone encountering this issue i have found my fix and it works now with crypto-js authentication.
Silly mistake from me not building the string up properly.
just update the script mentioned in my question with the following.
BROKEN
signatureString += 'digest: SHA-256=' + digest + '\n';
FIX
signatureString += 'digest: ' + digest + '\n';

Related

How can I write HTTP POST request multipart/form-data myself?

I want to send a POST request to server in multipart/form-data contents.
I have to write the request statement myself, without any high-level API
because it has to be sent as an AT command of the modem.
The curl command below is a command to test the server's API, and this is what I want to construct myself.
# This is what I want to construct myself.
curl -X POST $API_ENDPOINT \
-F time=yyyy-mm-dd-hh:mm:ss \
-F event=1 \
-F rssi=31 \
-F battery=80 \
-F filename=test.jpg \
-F files=#test.jpg \ # Send an image from my local file system to server.
-w %{http_code}
echo "\r\n"
And the below is what I sent to my modem.
/* This is form for multipart/form-data. Is it right?
POST $API_ENDPOINT HTTP/1.1
Host: $HOST
Content-Length: $body_length
Content-Type: multipart/form-data; boundary="boundary"
--boundary
Content-Disposition: form-data; name="files"; filename="example.jpg"
Content-Type: image/jpg
--boundary--
*/
// Below C++ code was written for the above POST request.
std::string filename = "example.jpg";
std::string filePath = "example.jpg";
std::string body =
std::string("--boundary\r\n") +
"Content-Disposition: form-data; name=\"files\"; filename=\"" + filePath + "\"\r\n" +
"Content-Type: image/jpg\r\n" +
"\r\n" +
"--boundary--\r\n";
std::string header =
std::string("POST ") + url + " HTTP/1.1\r\n" +
"Host: " + host + "\r\n" +
"Content-Length: " + std::to_string(body.length()) + "\r\n" +
"Content-Type: multipart/form-data; boundary=\"boundary\"\r\n" +
"\r\n";
std::string data = header + body;
... and this is the server log.
Error: MultipartParser.end(): stream ended unexpectedly: state = PART_DATA
This is my question.
How can I add fields(time, event, rssi, etc) in the request body? The server seems getting each fields as <key: value> format. How can I add it in multipart/form-data?
Is it correct to attach an image file like that? In the curl command, I wrote the path of my local image file (-F files) and the name that this image file will be stored on the server (-F filename). How should I reflect this in my request form?
Thanks brothers
I did it! Right that.
/*
POST $API_ENDPOINT HTTP/1.1
Host: $HOST
Content-Length: $body_length
Content-Type: multipart/form-data; boundary="boundary"
--boundary
Content-Type: text/plain
Content-Disposition: form-data; name="time"
yyyy-mm-dd-hh:mm:ss
--boundary
Content-Type: text/plain
Content-Disposition: form-data; name="event"
1
--boundary
Content-Type: text/plain
Content-Disposition: form-data; name="rssi"
31
--boundary
Content-Type: text/plain
Content-Disposition: form-data; name="battery"
99
--boundary
Content-Type: text/plain
Content-Disposition: form-data; name="filename"
example.jpg
--boundary
Content-Type: image/jpg
Content-Disposition: form-data; name="files"; filename="example.jpg"
....binary bytes of example.jpg...
--boundary--
*/
const int fd = // File descriptor of my serial port
const std::string host = // host
const std::string uri = // uri
const int tryout = 10 // for modem
std::string filename = "1996-03-05.jpg";
std::string filePath = "1996-03-05.jpg";
std::ifstream bin(filePath, std::ios::binary);
std::string imageBin((std::istreambuf_iterator<char>(bin)), std::istreambuf_iterator<char>());
std::string TIMESTAMP = "1996-03-05";
std::string event = "1";
std::string rssi = "31";
std::string battery = "90";
atcmd::__sendATcmd(fd, "AT+QHTTPCFG=\"contextid\",1\r");
atcmd::__readBufferUntil(fd, "\r\nOK\r\n", tryout);
atcmd::__sendATcmd(fd, "AT+QHTTPCFG=\"contenttype\",3\r"); // 3: multipart/form-data
atcmd::__readBufferUntil(fd, "\r\nOK\r\n", tryout);
atcmd::__sendATcmd(fd, "AT+QHTTPCFG=\"requestheader\",1\r");
atcmd::__readBufferUntil(fd, "\r\nOK\r\n", tryout);
const std::string fullUrl = "http://" + host + uri;
atcmd::__sendATcmd(fd, ("AT+QHTTPURL=" + std::to_string(fullUrl.length()) + "\r").c_str());
atcmd::__readBufferUntil(fd, "\r\nCONNECT\r\n", tryout);
atcmd::__sendATcmd(fd, fullUrl.c_str());
atcmd::__readBufferUntil(fd, "\r\nOK\r\n", tryout);
std::string body_fields = (
std::string("--boundary\r\n") +
"Content-Type: text/plain\r\n" +
"Content-Disposition: form/data; name=\"time\"\r\n" +
"\r\n" +
TIMESTAMP + "\r\n" +
"--boundary\r\n" +
"Content-Type: text/plain\r\n" +
"Content-Disposition: form/data; name=\"event\"\r\n" +
"\r\n" +
event + "\r\n" +
"--boundary\r\n" +
"Content-Type: text/plain\r\n" +
"Content-Disposition: form/data; name=\"rssi\"\r\n" +
"\r\n" +
rssi + "\r\n" +
"--boundary\r\n" +
"Content-Type: text/plain\r\n" +
"Content-Disposition: form/data; name=\"battery\"\r\n" +
"\r\n" +
battery + "\r\n" +
"--boundary\r\n" +
"Content-Type: text/plain\r\n" +
"Content-Disposition: form/data; name=\"filename\"\r\n" +
"\r\n" +
filename + "\r\n"
);
std::string body_image = (
std::string("--boundary\r\n") +
"Content-Type: image/jpeg\r\n" +
"Content-Disposition: form-data; name=\"files\"; filename=\"" + filePath + "\"\r\n" +
"\r\n" +
imageBin + "\r\n" +
"--boundary--\r\n"
);
int bodyLen = body_fields.length() + body_image.length();
std::string header = (
std::string("POST ") + uri + " HTTP/1.1\r\n" +
"Host: " + host + "\r\n" +
"Content-Length: " + std::to_string(bodyLen) + "\r\n" +
"Content-Type: multipart/form-data; boundary=\"boundary\"\r\n" +
"\r\n"
);
const std::string dataLen = std::to_string(header.length() + bodyLen);
std::string maxInputBodyTime = "80";
std::string maxResponseTime = "80";
atcmd::__sendATcmd(fd, ("AT+QHTTPPOST="
+ dataLen + ","
+ maxInputBodyTime + ","
+ maxResponseTime + "\r").c_str());
atcmd::__readBufferUntil(fd, "\r\nCONNECT\r\n", tryout);
atcmd::__sendATcmd(fd, header.c_str());
atcmd::__sendATcmd(fd, body_fields.c_str());
atcmd::__sendATcmd(fd, body_image.c_str(), body_image.length());
atcmd::__readBufferUntil(fd, "\r\nOK\r\n", tryout);
atcmd::__sendATcmd(fd, "AT+QHTTPREAD=80\r");
std::cout << atcmd::__readBuffer(fd) << std::endl;

Send email with MailerSend API and R

I am trying to use the transaction email service MailerSend to send an email from R.
They have cURL instructions as to how to do this.
I don't think I have the formatting quite right as I get the error:
> response
Response [https://api.mailersend.com/v1/email]
Date: 2021-02-26 19:49
Status: 401
Content-Type: application/json
Size: 30 B
> rsp_content <- content(response, as = "parsed", type = "application/json")
> rsp_content
$message
[1] "Unauthenticated."
R Script to send an email
library("httr")
# MailerSend API Key
apiKeyMS <- Sys.getenv("MS_KEY")
# Email header info
email_from = "noreply#example.ca"
email_from_name = "Joe"
email_subject <- "Joe Update"
email_to <- "joe#gmail.com"
# Email Body
email_text <- "This is my email"
email_html <- "This is my email"
# Send Email
ms_url <- paste0("https://api.mailersend.com/v1/email")
response <- POST(ms_url,
add_headers("Authorization: Bearer" = apiKeyMS,
"X-Requested-With" = "XMLHttpRequest",
"Content-Type" = "application/json"),
body = list(
"subject" = email_subject,
"from" = email_from,
"from_name" = email_from_name,
"to" = email_to,
"text" = email_text,
"html" = email_html
), encode = "json")
#############################################################
Basic MailerSend cURL instructions
curl -X POST \
https://api.mailersend.com/v1/email \
-H 'Content-Type: application/json' \
-H 'X-Requested-With: XMLHttpRequest' \
-H 'Authorization: Bearer {place your token here without brackets}' \
-d '{
"from": {
"email": "your#email.com"
},
"to": [
{
"email": "your#email.com"
}
],
"subject": "Hello from MailerSend!",
"text": "Greetings from the team, you got this message through MailerSend.",
"html": "Greetings from the team, you got this message through MailerSend."
}'
I don't know R at all, but I would guess your bearer token is incorrect.
The header key is Authorization and the value should be "Bearer {place your token here without brackets}"
You have to have these three headers
-H 'Content-Type: application/json' \
-H 'X-Requested-With: XMLHttpRequest' \
-H 'Authorization: Bearer {place your token here without brackets}' \`

Correct HTTP response header

I am using Safari to test my C++ socket handler, I send a request to the application, in the address bar:
http://127.0.0.1:8124/?{%22module%22:%22mdFileIO%22,%22command%22:%22open%22}
In my application I send a response:
const QString CRLF("\r\n");
QString strContent(strResponse)
,strDtNow(QDateTime::currentDateTime().toUTC().toString("ddd, dd MMM yyyy hh:mm:ss"))
,strHdr = "200 OK" + CRLF
+ "Content-Type: application/json" + CRLF
+ "Content-Length: " + QString::number(strContent.length()) + CRLF
+ "Date: " + strDtNow + " GMT" + CRLF + CRLF;
strResponse = strHdr + strContent;
In the above 'strContent' contains:
{"ack":"ack","module":"mdFileIO","time":"2020-10-05 18:00:19"}
The output for the response looks like this:
200 OK\r\nContent-Type: application/json\r\nContent-Length: 62\r\nDate: Mon, 05 Oct 2020 18:25:59 GMT\r\n\r\n{\"ack\":\"ack\",\"module\":\"mdFileIO\",\"time\":\"2020-10-05 18:25:59\"}
The return from write() is 161. Safari shows the following:
A couple of errors in the header:
The header should have started with "HTTP/1.1 "
The Content-Type should have been: "application/jsonrequest"

Lua Envoy upstream proxy

im looking to replace some login logic in on kong, for permission checks on a specific url (like upstream) to an envoy filter in istio.
apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
name: api-auth
namespace: api
spec:
workloadLabels:
app: api
filters:
- listenerMatch:
listenerType: SIDECAR_INBOUND
listenerProtocol: HTTP
filterName: envoy.lua
filterType: HTTP
filterConfig:
inlineCode: |
function version()
return "v1"
end
function log(handle, value)
handle:logInfo(version() .. ": " .. value)
end
function dump(o)
if type(o) == 'table' then
local s = '{ '
for k,v in pairs(o) do
if type(k) ~= 'number' then k = '"'..k..'"' end
s = s .. '['..k..'] = ' .. dump(v) .. ','
end
return s .. '} '
else
return tostring(o)
end
end
function is_empty(value)
return value == nil or value == ""
end
function get_header(handle, header)
return handle:headers():get(header)
end
function envoy_on_request(request_handle)
local auth_host = "auth-service.services.svc.cluster.local"
local path = "/api/v1/has-permission"
local cluster = "outbound|8080||" .. auth_host
local request_headers = {
[":method"] = "POST",
[":path"] = path,
[":authority"] = auth_host,
["Authorization"] = get_header(request_handle, "Authorization")
}
local request_body = ""
local timeout = 5000 --ms
log(request_handle, "Sending auth request, headers: " .. dump(request_headers) .. ", request_body: " .. request_body .. ", timeout: " .. timeout)
local response_headers, response_body = request_handle:httpCall(
tostring(cluster),
request_headers,
request_body,
timeout
)
log(request_handle, "response_headers: " .. dump(response_headers))
log(request_handle, "response_body: " .. dump(response_body))
if tonumber(response_headers[":status"]) ~= 200 then
log(request_handle, "Key Authentication Failed")
request_handle:respond(
{[":status"] = response_headers[":status"]},
response_body
)
do return end
end
end
so this is my lua, but im still missing something, i need to send extra parameters on my body post request.
example working curl:
curl -i 'https://foo-api.com/list' \
-H 'Connection: keep-alive' \
-H 'Pragma: no-cache' \
-H 'Cache-Control: no-cache' \
-H 'AuthCode: cmdpby50ZWl4ZWlyYUBqdW1pYS5jb20iLCJleHAiOjE1ODUwNDg2MjIsImlzcyI6ImZpcmV3b3JrcyJ9.JkvIhmQuumS32HhSzKuAhpPvjLVwOrRJXwajMjBU9Ag' \
-H 'Accept-Language: en' \
-H 'Authorization: Bearer 6InNlcmdpby50ZWl4ZWlyYUBqdW1pYS5jb20iLCJleHAiOjE1ODUwNDg2MjIsImlzcyI6ImZpcmV3b3JrcyJ9.JkvIhmQuumS32HhSzKuAhpPvjLVwOrRJXwajMjBU9Ag' \
-H 'Accept: application/json, text/plain, */*' \
-H 'Sec-Fetch-Dest: empty' \
-H 'application: COMPANYCODE'
how iam supposed to send this kind of content inside the post using lua?
thanks and best regards

Curl dropbox request in R using httr

I have this sample curl request:
curl -X POST https://content.dropboxapi.com/2/files/upload \
--header "Authorization: Bearer fakeaccesstoke12345" \
--header "Dropbox-API-Arg: {\"path\": \"/Homework/math/Matrices.txt\",\"mode\": \"add\"}" \
--header "Content-Type: application/octet-stream" \
--data-binary #local_file.txt
Which I tried translating into httr like this:
httr::POST(
"https://content.dropboxapi.com/2/files/upload",
add_headers(Authorization = "Bearer fakeaccesstoke12345",
`Dropbox-API-Arg` = paste("{\"path\": \"/folder/", FileName, "\"mode\": \"add\"}", sep = ''),
`Content-Type` = "Content-Type: application/octet-stream"
)
)
This is not working. I'm not sure what the --data-binary is doing either. The docs don't seem to say anything about it so I wonder if this is some standard parameter in HTTP.
The docs for the upload enpoint can be found here if needed.
library(httr)
library(jsonlite)
POST(
'https://content.dropboxapi.com/2/files/upload',
add_headers(
Authorization = "Bearer <token>",
`Dropbox-API-Arg` =
jsonlite::toJSON(
list(path = "/books.csv", mode = "add", autorename = TRUE, mute = FALSE),
auto_unbox = TRUE
)
),
content_type("application/octet-stream"),
body = upload_file("books.csv")
)

Resources