2
votes

I need help constructing the Authorization header to PUT a block blob.

PUT\n\n\n11\n\n\n\n\n\n\n\n\nx-ms-blob-type:BlockBlob\nx-ms-date:Sat, 25 Feb 2017 22:20:13 GMT\nx-ms-version:2015-02-21\n/myaccountname/mycontainername/blob.txt\n

I take this, UTF 8 encode it. Then I take my access key in my Azure account and HMAC sha256 this UTF 8 encoded string with the key. Then I output that in base64. Let's call this output string.

My authorization header looks like this: SharedKey myaccountname:output string

It is not working.

The header in Postman also has x-ms-blob-type, x-ms-date, x-ms-version, Content-Length, and Authorization. The body for now says hello world.

Can anyone help me make this successful request in Postman?

<?xml version="1.0" encoding="utf-8"?>
<Error>
    <Code>AuthenticationFailed</Code>
    <Message>Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature.
RequestId:cdeb9a5e-0001-0029-5fb5-8f7995000000
Time:2017-02-25T22:22:32.0300016Z</Message>
    <AuthenticationErrorDetail>The MAC signature found in the HTTP request 'jiJtirohvi1syXulqkPKESnmQEJI4GpDU5JBn7BM/xY=' is not the same as any computed signature. Server used following string to sign: 'PUT


11

text/plain;charset=UTF-8






x-ms-date:Sat, 25 Feb 2017 22:20:13 GMT
x-ms-version:2015-02-21
/myaccountname/mycontainername/blob.txt'.</AuthenticationErrorDetail>
</Error>

EDIT:

First, I want to thank you and everyone who responded. I truly truly appreciate it. I have one last question and then I think I'll be set!! I'm not using that code - I'm doing this all by hand. If I have my key: X2iiy6v47j1jZZH5555555555zzQRrIAdxxVs55555555555av8uBUNGcBMotmS7tDqas14gU5O/w== changed slightly for anonymity - do I decode it: using an online base64decoder. Then, when I have my string which now looks like this: PUT\n\n\n11\n\ntext/plain;charset=UTF-8\n\n\n\n\n\n\nx-ms-blob-type:BlockBlob\nx-ms-date:Mon, 27 Feb 2017 21:53:13 GMT\nx-ms-version:2015-02-21\n/myaccount/mycontainer/blob.txt\n so I run this in https://mothereff.in/utf-8 and then use this in HMAC with my decoded key: https://www.liavaag.org/English/SHA-Generator/HMAC/ - using sha256 and base64 at the end.

Is that how I get the correct string to put here?: SharedKey myaccount:<string here>

2
With the tool that you mentioned to generated the code doesn't match signature due to the "\n" charaters. I wrote an online tool to generate signature. I also updated the answers.Tom Sun - MSFT

2 Answers

1
votes

I believe there's an issue with how you're specifying StringToSign here:

PUT\n\n\n11\n\n\n\n\n\n\n\n\nx-ms-blob-type:BlockBlob\nx-ms-date:Sat, 25 Feb 2017 22:20:13 GMT\nx-ms-version:2015-02-21\n/myaccountname/mycontainername/blob.txt\n

If you notice the error message returned from the server, string to sign by server is different than yours and the difference is that the server is using Content-Type (text/plain;charset=UTF-8) in signature calculation while you're not. Please include this content type in your code and things should work just fine.

Here's the sample code (partial only) I used:

        var requestMethod = "PUT";
        var urlPath = "test" + "/" + "myblob.txt";
        var storageServiceVersion = "2015-12-11";
        var date = DateTime.UtcNow.ToString("R", CultureInfo.InvariantCulture);
        var blobType = "BlockBlob";
        var contentBytes = Encoding.UTF8.GetBytes("Hello World");
        var canonicalizedResource = "/" + accountName + "/" + urlPath;
        var canonicalizedHeaders = "x-ms-blob-type:" + blobType + "\nx-ms-date:" + date + "\nx-ms-version:" + storageServiceVersion + "\n";
        var stringToSign = requestMethod + "\n" +
            "\n" + //Content Encoding
            "\n" + //Content Language
            "11\n" + //Content Length
            "\n" + //Content MD5
            "text/plain;charset=UTF-8" + "\n" + //Content Type
            "\n" + //Date
            "\n" + //If - Modified - Since
            "\n" + //If - Match
            "\n" + //If - None - Match
            "\n" + //If - Unmodified - Since
            "\n" + //Range +
           canonicalizedHeaders +
           canonicalizedResource;
        string authorizationHeader = GenerateSharedKey(stringToSign, accountKey, accountName);


    private static string GenerateSharedKey(string stringToSign, string key, string account)
    {
        string signature;
        var unicodeKey = Convert.FromBase64String(key);
        using (var hmacSha256 = new HMACSHA256(unicodeKey))
        {
            var dataToHmac = Encoding.UTF8.GetBytes(stringToSign);
            signature = Convert.ToBase64String(hmacSha256.ComputeHash(dataToHmac));
        }
        return string.Format(CultureInfo.InvariantCulture, "{0} {1}:{2}", "SharedKey", account, signature);
    }
0
votes

According to your error message, it indicates that authorization signature is incorrect.

If the Content-Type "text/plain; charset=UTF-8" is not included in the header, please add it in the stringTosign and postman.

When we try to get the signature, we need to make sure the length of the blob.txt matches the Content length in the stringTosign. That means request body length should match the content length in the stringTosign.

I test it with Postman, it works correctly. We can get the signature with the code in another SO Thread. The following is my detail steps

  1. Add the following header

enter image description here

  1. Add the request body (example: Hello World)

enter image description here

  1. Send the put blob request.

enter image description here

Update :

Please have a try to use the online tool to generate signature for test.