Requests of Azure Blob Storage need to be authorized. To authorize with shared key (Access Key of your Azure storage account) , requests require at least two headers: Date (or x-ms-date) header and Authorization header. This article will discuss the formats of these headers and how to generate the shared key signature by using Google Apps Script.

Format of Date Header

  • “Date” or “x-ms-date” can be used in the header key field.
  • If both “Date” and “x-ms-date” headers are on the requests, “x-ms-date” will be used.
  • Value of the header should be UTC timestamp format. For example: Fri, 26 Jun 2015 23:39:12 GMT. You can generate it with:
var now = new Date().toUTCString();

Format of Authorization Header

Authorization="[SharedKey|SharedKeyLite] <AccountName>:<Signature>"
  • SharedKey or SharedKeyLite: authorization scheme.
  • AccountName: Azure storage account name
  • Signature: signed signature string with HMAC-SHA256 and Base64 encoding

How to sign and encode the signature

  1. UTF-8 encode the signature string the next section will discuss
  2. Base64 decode the Azure storage account shared key (Access Key)
  3. Call HMAC-SHA256 on the results of step 1 and 2
  4. Base64 encode the result of step 3

Base64(HMAC-SHA256(UTF8(StringToSign), Base64.decode(<shared_key>)))

Format of signature string

StringToSign = VERB + "\n" +  
               Content-Encoding + "\n" +  
               Content-Language + "\n" +  
               Content-Length + "\n" +  
               Content-MD5 + "\n" +  
               Content-Type + "\n" +  
               Date + "\n" +  
               If-Modified-Since + "\n" +  
               If-Match + "\n" +  
               If-None-Match + "\n" +  
               If-Unmodified-Since + "\n" +  
               Range + "\n" +  
               CanonicalizedHeaders +   
               CanonicalizedResource;

Take “Get Blob” (download file) as an example:

GET\n /*HTTP Verb*/  
\n    /*Content-Encoding*/  
\n    /*Content-Language*/  
\n    /*Content-Length (empty string when zero)*/  
\n    /*Content-MD5*/  
\n    /*Content-Type*/  
\n    /*Date*/  
\n    /*If-Modified-Since */  
\n    /*If-Match*/  
\n    /*If-None-Match*/  
\n    /*If-Unmodified-Since*/  
\n    /*Range*/  
x-ms-date:Fri, 26 Jun 2015 23:39:12 GMT\nx-ms-version:2015-02-21\n    /*CanonicalizedHeaders*/  
/myaccount /mycontainer\ncomp:metadata\nrestype:container\ntimeout:20    /*CanonicalizedResource*/

“Put Blob” (upload/update file) example

PUT\n /*HTTP Verb*/  
\n    /*Content-Encoding*/  
\n    /*Content-Language*/  
6729182\n    /*Content-Length (empty string when zero)*/  
\n    /*Content-MD5*/  
\n    /*Content-Type*/  
\n    /*Date*/  
\n    /*If-Modified-Since */  
\n    /*If-Match*/  
\n    /*If-None-Match*/  
\n    /*If-Unmodified-Since*/  
\n    /*Range*/  
x-ms-blob-type:BlockBlob\nx-ms-date:Fri, 26 Jun 2015 23:39:12 GMT\nx-ms-version:2015-02-21\n
/myaccount /mycontainer\ncomp:metadata\nrestype:container\ntimeout:20

Generate the Signature

In the procedure of sign and encode the signature, the first step is to encode the signature string with UTF-8. We can do that in Google Apps Script by using:

Utilities.newBlob("").setDataFromString(string).getBytes()

We can use the following code is to generate the the signature (using “Get Blob” as the example):

function signAzureBlobKeyGET(){

  var verb = 'GET';
  var headers = '\n\n\n\n\n\n\n\n\n\n\n\n';
  var msDate = 'x-ms-date:';
  var msVersion = 'x-ms-version:2020-04-08';
  var now = new Date().toUTCString();
  msDate = msDate + now;
  var cHeaders = msDate + '\n' + msVersion + '\n';
  var cResource = '/'+ azureStorageAccount + '/' + azureContainer + '/' + azureBlob;
  var string = verb + headers + cHeaders + cResource;
  var utf8bytes = Utilities.newBlob("").setDataFromString(string).getBytes();
  var decodeKey = Utilities.base64Decode(azureAccessKey);
  var shaSig = Utilities.computeHmacSha256Signature(utf8bytes, decodeKey);
  var signature = Utilities.base64Encode(shaSig);
  return signature;

}

Example original signature string:

GET











x-ms-date:Sat, 03 Jul 2021 06:01:43 GMT
x-ms-version:2020-04-08
/stgaccountname/examplecontainer/signature.mp3

And the signed signature will be something like this:

PK4b/Hye7QtXDpy8Ub8+LQ6Zu3aOpV9qQvzORuPkxm0=

So your Authorization Header will be (JSON format):

"Authorization": "SharedKey stgaccountname:PK4b/Hye7QtXDpy8Ub8+LQ6Zu3aOpV9qQvzORuPkxm0="

Full GET HTTP Header example

Remember to add “x-ms-date” and “x-ms-version” to HTTP header. So the complete HTTP header you should add is:

{
    'x-ms-date': "Sat, 03 Jul 2021 06:01:43 GMT",
    'x-ms-version': "2020-04-08",
    'Authorization': "SharedKey stgaccountname:PK4b/Hye7QtXDpy8Ub8+LQ6Zu3aOpV9qQvzORuPkxm0="
}

Full PUT HTTP Header example

In additional to the header content shown above, we need to add ‘x-ms-blob-type’ and ‘Content-Length’ to the header if you want to add/update the files. Note that ‘Content-Length’ should be placed in the option portion of the UrlFetchApp.fetch() call.

Here is the example:

var res = UrlFetchApp.fetch(azureBlobURL, {
      'headers': {
      'x-ms-blob-type': 'BlockBlob',
      'Authorization': 'SharedKey accntname:PK4b/Hye7QtXDpy8Ub8+LQ6Zu3aOpV9qQvzORuPkxm0=',
      'x-ms-date': 'Sat, 03 Jul 2021 06:01:43 GMT',
      'x-ms-version': '2020-04-08'
    },
    'contentLength': content.length,
    'method': 'put',
    'muteHttpExceptions': true,
    'payload': content
});

這個網站採用 Akismet 服務減少垃圾留言。進一步了解 Akismet 如何處理網站訪客的留言資料