I need to do this all within Postman application. I have found examples that use blob and tables but they didn't seem to fit with the queue storage. I think the biggest problem is that I am unable to create the signature part properly.
I believe I managed to execute Get Message in postman but I get "Server failed to authenticate the request." error upon Post request. The message I'm trying to post is in XML format and uses the same pre-request Script as the Get.
Pre-request Script of the Post and Get request (copied from online sources):
const storageAccount = pm.variables.get('azure_storage_account');
const accountKey = pm.variables.get('azure_storage_key');
pm.variables.set("header_date", new Date().toUTCString());
// Get hash of all header-name:value
const headers = pm.request.getHeaders({ ignoreCase: true, enabled: true });
// Construct Signature value for Authorization header
var signatureParts = [
pm.request.method.toUpperCase(),
headers["content-encoding"] || "",
headers["content-language"] || "",
headers["content-length"] || "",
// pm.request.body ? pm.request.body.toString().length || "" : "",
headers["content-md5"] || "",
headers["content-type"] || "",
headers["x-ms-date"] ? "" : (pm.variables.get("header_date") || ""),
headers["if-modified-since"] || "",
headers["if-match"] || "",
headers["if-none-match"] || "",
headers["if-unmodified-since"] || "",
headers["range"] || ""
];
// Construct CanonicalizedHeaders
const canonicalHeaderNames = [];
Object.keys(headers).forEach(key => {
if (key.startsWith("x-ms-")) {
canonicalHeaderNames.push(key);
}
});
// Sort headers lexographically by name
canonicalHeaderNames.sort();
const canonicalHeaderParts = [];
canonicalHeaderNames.forEach(key => {
let value = pm.request.getHeaders({ ignoreCase: true, enabled: true })[key];
// Populate variables
value = pm.variables.replaceIn(value);
// Replace whitespace in value but not if its within quotes
if (!value.startsWith("\"")) {
value = value.replace(/\s+/, " ");
}
canonicalHeaderParts.push(`${key}:${value}`);
});
// Add headers to signature
signatureParts.push.apply(signatureParts, canonicalHeaderParts);
// Construct CanonicalizedResource
const canonicalResourceParts = [
`/${pm.variables.get("azure_storage_account")}${pm.request.url.getPath()}`
];
const canonicalQueryNames = [];
pm.request.url.query.each(query => {
canonicalQueryNames.push(query.key.toLowerCase());
});
canonicalQueryNames.sort();
canonicalQueryNames.forEach(queryName => {
const value = pm.request.url.query.get(queryName);
// NOTE: This does not properly explode multiple same query params' values
// and turn them into comma-separated list
canonicalResourceParts.push(`${queryName}:${value}`);
});
// Add resource to signature
signatureParts.push.apply(signatureParts, canonicalResourceParts);
console.log("Signature Parts", signatureParts);
// Now, construct signature raw string
const signatureRaw = signatureParts.join("\n");
console.log("Signature String", JSON.stringify(signatureRaw));
// Hash it using HMAC-SHA256 and then encode using base64
const storageKey = pm.variables.get("azure_storage_key");
const signatureBytes = CryptoJS.HmacSHA256(signatureRaw, CryptoJS.enc.Base64.parse(storageKey));
const signatureEncoded = signatureBytes.toString(CryptoJS.enc.Base64);
console.log("Storage Account", pm.variables.get("azure_storage_account"));
console.log("Storage Key", storageKey);
// Finally, make it available for headers
pm.variables.set("header_authorization",
`SharedKey ${pm.variables.get("azure_storage_account")}:${signatureEncoded}`);
Headers in Postman:
Headers and URI of Request
Does anyone have working examples or knows where to move from here?
Edit:
Adding console and Error images:
Console output censored for safety
Error output censored for safety
As you said it is working well for Get And if using SAS ,it maybe permission issue .make sure to Storage-Queue-Contributor permissions on the storage queue.
There can be many reasons for this error if using SAS :
Check if you have insufficient SAS Permissions. Check if you marked read, write,list permissioms .Or try generating the new SAS key .
Make sure request does not include any empty headers when it is being access programmatically. If the value of a particular header is empty (or null), the header should be excluded from the request.
Also if above are not the reasons , try upgrading versions of sdks
4.Do check for proper encoding ex: UTF-8.
See Azure Storage Queue via REST API c# using Shared Key Authentication - Stack Overflow
References:
c# - The MAC signature found in the HTTP request ' ' is not the
same as any computed signature. Server used following string to
sign: 'PUT - Stack Overflow
Authorize with Shared Key (REST API) - Azure Storage | Microsoft
Docs
rest - The MAC signature found in the HTTP request '...' is not the
same as any computed signature - Stack Overflow
Related
I am using an example (Node.js Create Egypt ITIDA CAdES-BES Signature with Automatic JSON Canonicalization) but I always get this error ( 4043 4043:message-digest attribute value does not match calculated value[message-digest attribute value does not match calculated value] ).
Can you help me with the solution?
Code Used:
// This example assumes the Chilkat API to have been previously unlocked.
// See Global Unlock Sample for sample code.
var crypt = new chilkat.Crypt2();
crypt.VerboseLogging = true;
var cert = new chilkat.Cert();
cert.VerboseLogging = true;
// Set the smart card PIN, which will be needed for signing.
cert.SmartCardPin = "12345678";
// There are many ways to load the certificate.
// This example was created for a customer using an ePass2003 USB token.
// Assuming the USB token is the only source of a hardware-based private key..
var success = cert.LoadFromSmartcard("");
if (success !== true) {
console.log(cert.LastErrorText);
return;
}
// Tell the crypt class to use this cert.
success = crypt.SetSigningCert(cert);
if (success !== true) {
console.log(crypt.LastErrorText);
return;
}
var cmsOptions = new chilkat.JsonObject();
// Setting "DigestData" causes OID 1.2.840.113549.1.7.5 (digestData) to be used.
cmsOptions.UpdateBool("DigestData",true);
cmsOptions.UpdateBool("OmitAlgorithmIdNull",true);
// Indicate that we are passing normal JSON and we want Chilkat do automatically
// do the ITIDA JSON canonicalization:
cmsOptions.UpdateBool("CanonicalizeITIDA",true);
crypt.CmsOptions = cmsOptions.Emit();
// The CadesEnabled property applies to all methods that create CMS/PKCS7 signatures.
// To create a CAdES-BES signature, set this property equal to true.
crypt.CadesEnabled = true;
crypt.HashAlgorithm = "sha256";
var jsonSigningAttrs = new chilkat.JsonObject();
jsonSigningAttrs.UpdateInt("contentType",1);
jsonSigningAttrs.UpdateInt("signingTime",1);
jsonSigningAttrs.UpdateInt("messageDigest",1);
jsonSigningAttrs.UpdateInt("signingCertificateV2",1);
crypt.SigningAttributes = jsonSigningAttrs.Emit();
// By default, all the certs in the chain of authentication are included in the signature.
// If desired, we can choose to only include the signing certificate:
crypt.IncludeCertChain = false;
var jsonToSign = "{ ... }";
// Create the CAdES-BES signature.
crypt.EncodingMode = "base64";
// Make sure we sign the utf-8 byte representation of the JSON string
crypt.Charset = "utf-8";
var sigBase64 = crypt.SignStringENC(jsonToSign);
if (crypt.LastMethodSuccess == false) {
console.log(crypt.LastErrorText);
return;
}
console.log("Base64 signature:");
console.log(sigBase64);
Check to see if the information at this Chilkat blog post helps: https://cknotes.com/itida-4043message-digest-attribute-value-does-not-match-calculated-value/
See this example for details about debugging and what you can send to Chilkat: https://www.example-code.com/nodejs/itida_egypt_debug.asp
We were having this error, until we were advised of not using any null values in the json file. So, pls try to replace any null values in json file with "".
In a signup custom policy, after the user is created, I want to add him or her to a group. I tried to do it the same way I get the group membership in my signin policy, with a custom Azure function that calls the GraphAPI.
For teststing purpose, I first tried calling GraphAPI with Postman to see if it works. I got it working following the docs and came back with this query :
POST https://graph.microsoft.com/v1.0/groups/{{b2c-beneficiaire-group-id}}/members/$ref
Body:
{
"#odata.id": "https://graph.microsoft.com/v1.0/users/{{b2c-user-id}}"
}
And that work just fine. I get a 204 response and the user is in fact now a member of the group.
Now here's the part where I try to replicate it in my Azure function :
var url = $"https://graph.microsoft.com/v1.0/groups/{groupId}/members/$ref)";
var keyOdataId = "#odata.id";
var valueODataId = $"https://graph.microsoft.com/v1.0/users/{userId}";
var bodyObject = new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>(keyOdataId, valueODataId)
};
var jsonData = $#"{{ ""{keyOdataId}"": ""{valueODataId}"" }}";
var groupBody = new StringContent(jsonData, Encoding.UTF8, "application/json");
log.LogInformation($"{url} + body:{await groupBody.ReadAsStringAsync()}");
using (var response = await httpClient.PostAsync(url, groupBody))
{
log.LogInformation("HttpStatusCode=" + response.StatusCode.ToString());
if (!response.IsSuccessStatusCode)
{
throw new InvalidOperationException($"{response.StatusCode} - Reason:{response.ReasonPhrase}. Content:{await response.Content.ReadAsStringAsync()}");
}
}
I've tried a few variations (with HttpRequest and other things) but I always end up with an Odata error :
"BadRequest","message":"The request URI is not valid. Since the segment 'members' refers to a collection,
this must be the last segment in the request URI or it must be followed by an function or action
that can be bound to it otherwise all intermediate segments must refer to a single resource."
From what I see it is related to the OData query (the $ref part). Do you have any idea about what do I have to do to make it work?
It looks like a typo in your url which ends with )
var url = $"https://graph.microsoft.com/v1.0/groups/{groupId}/members/$ref)";
A recent school project I was assigned has a coding challenge we have to complete. The challenge has multiple parts, and the final part is uploading to a private GitHub repo and submitting a completion request by making a POST request under certain conditions.
I have successfully completed the other parts of the challenge and am stuck on submitting the request. The submission has to follow these rules:
Build your solution request
First, construct a JSON string like below:
{
"github_url": "https://github.com/YOUR_ACCOUNT/GITHUB_REPOSITORY",
"contact_email": "YOUR_EMAIL"
}
Fill in your email address for YOUR_EMAIL, and the private Github repository with your solution in YOUR_ACCOUNT/GITHUB_REPOSITORY.
Then, make an HTTP POST request to the following URL with the JSON string as the body part.
CHALLENGE_URL
Content type
The Content-Type: of the request must be application/json.
Authorization
The URL is protected by HTTP Basic Authentication, which is explained on Chapter 2 of RFC2617, so you have to provide an Authorization: header field in your POST request.
For the userid of HTTP Basic Authentication, use the same email address you put in the JSON string.
For the password , provide a 10-digit time-based one time password conforming to RFC6238
TOTP.
Authorization password
For generating the TOTP password, you will need to use the following setup:
You have to generate a correct TOTP password according to RFC6238
TOTP's Time Step X is 30 seconds. T0 is 0.
Use HMAC-SHA-512 for the hash function, instead of the default HMAC-SHA-1.
Token shared secret is the userid followed by ASCII string value "APICHALLENGE" (not including double quotations).
Shared secret examples
For example, if the userid is "email#example.com", the token shared secret is "email#example.comAPICHALLENGE" (without quotes).
If your POST request succeeds, the server returns HTTP status code 200 .
I have tried to follow this outline very carefully, and testing my work in different ways. However, it seems I can't get it right. We are supposed to make the request from a Node server backend. This is what I have done so far. I created a new npm project with npm init and installed the dependencies you will see in the code below:
const axios = require('axios');
const base64 = require('base-64');
const utf8 = require('utf8');
const { totp } = require('otplib');
const reqJSON =
{
github_url: GITHUB_URL,
contact_email: MY_EMAIL
}
const stringData = JSON.stringify(reqJSON);
const URL = CHALLENGE_URL;
const sharedSecret = reqJSON.contact_email + "APICHALLENGE";
totp.options = { digits: 10, algorithm: "sha512" }
const myTotp = totp.generate(sharedSecret);
const isValid = totp.check(myTotp, sharedSecret);
console.log("Token Info:", {myTotp, isValid});
const authStringUTF = reqJSON.contact_email + ":" + myTotp;
const bytes = utf8.encode(authStringUTF);
const encoded = base64.encode(bytes);
const createReq = async () =>
{
try
{
// set the headers
const config = {
headers: {
'Content-Type': 'application/json',
"Authorization": "Basic " + encoded
}
};
console.log("Making req", {URL, reqJSON, config});
const res = await axios.post(URL, stringData, config);
console.log(res.data);
}
catch (err)
{
console.error(err.response.data);
}
};
createReq();
As far as I understand, I'm not sure where I'm making a mistake. I have tried to be very careful in my understanding of the requirements. I have briefly looked into all of the documents the challenge outlines, and gathered the necessary requirements needed to correctly generate a TOTP under the given conditions.
I have found the npm package otplib can satisfy these requirements with the options I have passed in.
However, my solution is incorrect. When I try to submit my solution, I get the error message, "Invalid token, wrong code". Can someone please help me see what I'm doing wrong?
I really don't want all my hard work to be for nothing, as this was a lengthy project.
Thank you so much in advance for your time and help on this. I am very grateful.
The Readme of the package otplib states:
// TOTP defaults
{
// ...includes all HOTP defaults
createHmacKey: totpCreateHmacKey,
epoch: Date.now(),
step: 30,
window: 0,
}
So the default value for epoch (T0) is Date.now() which is the RFC standard. The task description defines that T0 is 0.
You need to change the default value for epoch to 0:
totp.options = { digits: 10, algorithm: "sha512", epoch: 0 }
How do you use nlapiRequestURL to make a request to a service? My attempt below is failing with the error: UNEXPECTED_ERROR (output from NetSuites script execution log).
My service is set to run without login and works correctly when I directly access it through a browser using its url. Its just the request through nlapiRequestURL thats failing.
Any idea what could be going wrong?
// This code executes in Account.Model.js (register function)
// I am using my own netsuite user credential here
var cred = {
email: "MY_NETSUITE_EMAIL"
, account: "EXXXXX" // My account id
, role: "3" // Administrator
, password: "MY_NETSUITE_PASSWORD"
};
var headers = {"User-Agent-x": "SuiteScript-Call",
"Authorization": "NLAuth nlauth_account=" + cred.account + ", nlauth_email=" + cred.email +
", nlauth_signature= " + cred.password + ", nlauth_role=" + cred.role,
"Content-Type": "application/json"};
var payload = {
type: 'is_email_valid'
, email: 'spt015#foo.com'
};
// A raw request to the service works fine:
// http://mywebsite.com/services/foo.ss?type=is_email_valid&email=spt015#foo.com
// Error occurs on next line
var response = nlapiRequestURL(url, payload, headers);
You are attempting to call a non-Netsuite url with Netsuite authentication headers. You do not need that unless for some reason of your own you have implemented NS-style authorization on your service.
nlapiRequestURL does not automatically format a payload into a query string. If your service takes a posted JSON body then you need to call JSON.stringify(payload) e.g
var response = nlapiRequestURL(url, JSON.stringify(payload), headers);
If your service needs a query string like in your example then you need to construct a query string and append it to your service url. e.g.
var qs = '';
for(var k in payload) qs += k +'='+ uriEncodeComponent(payload[k]) +'&';
var response = nlapRequestURL(url +'?'+ qs.slice(0,-1), null, headers);
I would suggest changing your nlapiRequestURL to a GET instead of POST, and add the parameters to the url instead. Your function call will look like this instead.
nlapiRequestURL(url, null, headers, "GET")
I am working on a face recognition project with Microsoft Azure Cognitive services. Not quite sure why I am not able to correct my own JSON Malformed syntax I thought I nail this 6 months ago. I want to create a group name, so I call upon 'Person Group API' and everytime I follow MS example I get errors in my code however in the API testing Console no problems here is my code example borrow from MS site :
{ "error": { "code": "ResourceNotFound", "message": "The requested resource was not found." } }
and the code which is run in Console mode :
static async void CreateGroup()
{
string key1 = "YourKey";
// azure the one should work
var client = new HttpClient();
var queryString = HttpUtility.ParseQueryString(string.Empty);
// Request headers
client.DefaultRequestHeaders.Add
("Ocp-Apim-Subscription-Key", key1);
var uri = "https://westus.api.cognitive.microsoft.com/face/v1.0/
persongroups/{personGroupId}?" + queryString;
HttpResponseMessage response;
// Request body
string groupname = "myfriends";
string body = "{\"name\":\"" + groupname + ","+ "\"}";
// Request body
using (var content = new StringContent
(body, Encoding.UTF8, "application/json"))
{
await client.PostAsync(uri, content)
.ContinueWith(async responseTask =>
{
var responseBody = await responseTask.Result
.Content.ReadAsStringAsync();
Console.ForegroundColor = ConsoleColor.Yellow;
Console.WriteLine("Response: {0}", responseBody);
Console.WriteLine("");
Console.WriteLine("Group Created.... ");
Console.WriteLine("Hit ENTER to exit...");
Console.ReadKey();
});
response = await client.PutAsync(uri, content);
Console.WriteLine("what is this {0}", response.ToString());
Console.ReadKey();
}// end of using statement
}// end of CreateGroup
#endregion
I am guess here but I think its my JSON is malformed again and I just don't know what I am doing wrong again this time. According to the site the field name that I require to send over to ms is 'name' : 'userData' is optional.
Faced the similar issue, after adding "/detect" in the uri the issue fixed.
See the below
var uri = "https://westus.api.cognitive.microsoft.com/face/v1.0/detect
Also make sure the subscription key is valid.
Your request url must specify a group ID in place of where you have {personGroupId}. Per the spec the group ID must be:
User-provided personGroupId as a string. The valid characters include
numbers, English letters in lower case, '-' and '_'. The maximum
length of the personGroupId is 64.
Furthermore, the http verb needs to PUT, whereas you've made a client.PostAsync request. So you'll need to change that to client.PutAsync.
Microsoft provides a client library for C# for the Face API where you can find working C# code.
In python, simply this worked for me.
ENDPOINT='https://westcentralus.api.cognitive.microsoft.com'