Client applications have to make a request over HTTP/HTTPS to Azure Storage to access data in Azure storage account. As the resources are secured, so every request must be authorised to confirm that client is permitted to access the requested data. Azure Storage allows 4 different ways for authorising access to secured resources-
>>Azure Active Direcory (AAD) integration – Follow the steps in these articles to achieves this using Postman-
- create-an-azure-service-principal
- how-to-authenticate-azure-service-principal-with-client-secret-using-postman
- how-to-authenticate-service-principal-with-client_secret-in-pre-request-scripts-using-postman
- how-to-use-azure-blob-storage-service-rest-api-operations-using-postman
>> Shared Key Authorisation: We will detailed steps in this article on how to achieve this.
>> Shared Access Signature
>> Anonymous public read access
SHARED KEY Authorization:
The Blob, Queue, Table, and File services support the following Shared Key authorization schemes for version 2009-09-19 and later (for Blob, Queue, and Table service)
We will try to create a container in an storage account by authorising using Shared Key.
>>Open Postman and create a collection.
>> Add a PUT request to add a container (testconnt) in storage account (tblobaccountstorage). Create environment variable “header_date”, “azure_storage_account”, “azure_storage_key” and “header_authorization”.
Add the values to header as shown in screen shot
>> Now copy / paste the below script into Pre-Request tab
const crypto = require("crypto-js"); // Set Date header value for authorization // Should be UTC GMT string pm.environment.set("header_date", new Date().toUTCString()); console.log("header date", new Date().toUTCString()); // Sadness: https://github.com/postmanlabs/postman-app-support/issues/2922 var substituteEnvVars = function (varStr) { let match; let replacedVar = varStr; while ((match = /\{\{([^{}]*?)}}/g.exec(replacedVar)) !== null ) { if (!pm.variables.get(match[1])) { continue; } var envVar = new RegExp(RegExp.escape(match[0]), 'g'); replacedVar = replacedVar.replace(envVar, pm.variables.get(match[1])); } return replacedVar; }; // 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"] || "", 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); console.log("key: ", canonicalHeaderNames); } }); // Sort headers lexographically by name canonicalHeaderNames.sort(); const canonicalHeaderParts = []; canonicalHeaderNames.forEach(key => { let value = pm.request.getHeaders({ ignoreCase: true, enabled: true })[key]; console.log("value: ",value); // Populate variables value = substituteEnvVars(value); console.log("value: ",value); // Replace whitespace in value but not if its within quotes if (!value.startsWith("\"")) { value = value.replace(/\s+/, " "); console.log("value: ",value); } canonicalHeaderParts.push(`${key}:${value}`); console.log("canonicalHeaderParts: ",canonicalHeaderParts); }); // Add headers to signature signatureParts.push.apply(signatureParts, canonicalHeaderParts); // Construct CanonicalizedResource const canonicalResourceParts = [ `/${pm.environment.get("azure_storage_account")}${pm.request.url.getPath()}` ]; console.log("canonicalResourceParts: ",canonicalResourceParts); const canonicalQueryNames = []; pm.request.url.query.each(query => { canonicalQueryNames.push(query.key.toLowerCase()); console.log("canonicalQueryNames: ",query.key.toLowerCase()); }); canonicalQueryNames.sort(); canonicalQueryNames.forEach(queryName => { const value = pm.request.url.query.get(queryName); console.log("canonicalQueryNames: ",value); // NOTE: This does not properly explode multiple same query params' values // and turn them into comma-separated list canonicalResourceParts.push(`${queryName}:${value}`); console.log("canonicalResourcePartss: ",canonicalResourceParts); }); // 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.environment.get("azure_storage_key"); const signatureBytes = crypto.HmacSHA256(signatureRaw, crypto.enc.Base64.parse(storageKey)); const signatureEncoded = signatureBytes.toString(crypto.enc.Base64); console.log("Storage Account", pm.environment.get("azure_storage_account")); console.log("Storage Key", storageKey); // Finally, make it available for headers pm.variables.set("header_authorization", `SharedKey ${pm.environment.get("azure_storage_account")}:${signatureEncoded}`);
Note: More details about the script can be found here.
>>Save the request and click Send to create “testconnt” blob container in storage account using the SharedKey which is stored in environment variable “header_authorization”. Successfull submit will show