none
The MAC signature found in the HTTP request '***' is not the same as any computed signature. Server used following string to sign: 'POST

    Question

  • Hi,

    When trying with Postman sending a REST call to Azure Storage Queues I get:

    The MAC signature found in the HTTP request '***' is not the same as any computed signature. Server used following string to sign: 'POST.

    The code I have for creating the Authorization Header:

    var accountName = "my_account";
    string key = ConfigurationManager.AppSettings["my_access_key"];
    DateTime dt = DateTime.Now;
    string formattedDate = String.Format("{0:r}", dt);

    var canonicalizedHeaders = "x-ms-date:" + formattedDate + "\n" + "x-ms-version:2009-09-19" + "\n" ;
    var canonicalizedResource = "/my_account/myqueue/messages";
    var stringToSign = String.Format("POST,\n\n\n\n\n\n\n\n\n\n\n{0}{1}", canonicalizedHeaders, canonicalizedResource);
    stringToSign = HttpUtility.UrlEncode(stringToSign);
    HMACSHA256 hmac = new HMACSHA256(Encoding.UTF8.GetBytes(key));
    var signature = Convert.ToBase64String(hmac.ComputeHash(Encoding.UTF8.GetBytes(stringToSign)));
    var authorizationHeader = String.Format(CultureInfo.InvariantCulture, "SharedKey {0}:{1}", accountName, signature);
    return authorizationHeader;

    Anyone any idea what I'm missing/doing wrong?

    Additional question: do i have to create for every message I want to send a new Authorization header? Or is there an option (as with Service Bus Topics) to create a header that can be used for a certain timeframe?

    Thanks.


    • Edited by Guy Dillen Saturday, May 2, 2015 1:46 PM
    Saturday, May 2, 2015 1:38 PM

Answers

  • SAS, as you descibe I suppose can only be used from within .NET client and not when calling REST services from e.g. C/C++, ...?

    Not true. You basically get a SAS token that you can append to your URL (http://storage_account.queue.core.windows.net/myqueue/messages) and then make HTTP calls against that URL. With SAS you don't have to specify Authorization, x-ms-date or x-ms-version headers as they are included in your SAS token.

    Hope this helps.

    Monday, May 4, 2015 5:33 PM

All replies

  • One issue is with this line of code:

    HMACSHA256 hmac = new HMACSHA256(Encoding.UTF8.GetBytes(key));

    Please use the following:

    HMACSHA256 hmac = new HMACSHA256(Convert.FromBase64String(key));

    and that should take care of the problem.

    Regarding your question, "do i have to create for every message I want to send a new Authorization header? Or is there an option (as with Service Bus Topics) to create a header that can be used for a certain timeframe?"

    With your current approach, the answer is yes. What you can do is create a Shared Access Signature on the queue which will be valid for certain duration and then use that for posting messages to a queue using simple HttpWebRequest/HttpWebResponse.

    Hope this helps.

    Saturday, May 2, 2015 5:23 PM
  • One issue is with this line of code:
    HMACSHA256 hmac = new HMACSHA256(Encoding.UTF8.GetBytes(key));
    Please use the following:
    HMACSHA256 hmac = new HMACSHA256(Convert.FromBase64String(key));and that should take care of the problem.

    I changed the statement, but get still the same error, it drives me completely nuts:

    This is my stringToSign (before UrlEncode):

    GET











    x-ms-date:Mon, 04 May 2015 12:35:51 GMT
    x-ms-version:2012-02-12
    /storage_account/myqueue/messages

    This is my stringToSign after UrlEncode

    GET%0a%0a%0a%0a%0a%0a%0a%0a%0a%0a%0a%0ax-ms-date%3aMon%2c+04+May+2015+12%3a35%3a51+GMT%0ax-ms-version%3a2012-02-12%0a%2fstorage_account%2fmyqueue%2fmessages

    Thanks.

    Guy



    • Edited by Guy Dillen Monday, May 4, 2015 10:42 AM
    Monday, May 4, 2015 7:20 AM
  • When checking fiddler I see:

    HTTP/1.1 403 Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature.
    Content-Length: 627
    Content-Type: application/xml
    Server: Microsoft-HTTPAPI/2.0
    x-ms-request-id: 21a8d06f-0003-000c-637c-86c318000000
    Date: Mon, 04 May 2015 15:09:30 GMT

    <?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:21a8d06f-0003-000c-637c-86c318000000
    Time:2015-05-04T15:09:31.7380363Z</Message><AuthenticationErrorDetail>The MAC signature found in the HTTP request 'x1DtRvBYQjGj4sH7drcv917sc6NW5aFIDZCJd6th0wA=' is not the same as any computed signature. Server used following string to sign: 'GET



    x-ms-date:Mon, 04 May 2015 15:08:16 GMT
    /storage_account/myqueue/messages'.</AuthenticationErrorDetail></Error>

    obviously there's no server sign string?!



    • Edited by Guy Dillen Monday, May 4, 2015 3:11 PM
    Monday, May 4, 2015 2:52 PM
  • This is my code so far:

    private static string CreateAuthorizationHeader()
            {
                var method = "GET";                                                                 
                var dateInRfc1123Format = DateTime.UtcNow.ToString("R");
                var accountName = "storage_account";                                                
                var queueName = "myqueue";                                                          
                string key = ConfigurationManager.AppSettings["AccessKey"];
                var canonicalizedHeaders = String.Format("x-ms-date:{0}\nx-ms-version:2012-02-12\n", dateInRfc1123Format);
                var canonicalizedResource = String.Format("/{0}/{1}/messages", accountName, queueName);
           
                var stringToSign = String.Format("{0}\n\n\n\n\n\n\n\n\n\n\n\n{1}{2}", method, canonicalizedHeaders, canonicalizedResource);
                HMACSHA256 hmac = new HMACSHA256(Convert.FromBase64String(key));
                stringToSign = HttpUtility.UrlEncode(stringToSign);
                var signature = Convert.ToBase64String(hmac.ComputeHash(Encoding.UTF8.GetBytes(stringToSign)));
                var authorizationHeader = String.Format(CultureInfo.InvariantCulture, "SharedKey {0}:{1}", accountName, signature);
                return authorizationHeader;
            }

    Using Fiddler or Postman,

    http://storage_account.queue.core.windows.net/myqueue/messages

    I use the following headers:

    Authorization: the_value_of_authorizationHeader
    x-ms-date: the_value_of_dateInRfc1123Format 

    Anyone an idea what I'm missing? Thanks.



    • Edited by Guy Dillen Monday, May 4, 2015 3:48 PM
    Monday, May 4, 2015 3:40 PM
  • One more thing you could try is not URL encode your stringToSign variable and use it as is. See if that helps.

    Monday, May 4, 2015 4:48 PM
  • Thanks.

     not URL encode your stringToSign variable 

    I already left that statement out (without success).

    Monday, May 4, 2015 5:05 PM
  • Another thing I noticed is that you have specified x-ms-version in your stringToSign (in canonicalizedHeaders) however it seems you're not passing it as a request headers. You're only passing Authorization and x-ms-date headers. Could that be the issue?
    Monday, May 4, 2015 5:09 PM
  • indeed that was the issue. not it works. Many many thanks.

    I was confused as in https://msdn.microsoft.com/en-us/library/azure/dd179474.aspx it states this header value is optional

    x-ms-version

    Optional. Specifies the version of the operation to use for this request. For more information, seeVersioning for the Azure Storage Services.

    One last thing:

    Regarding your question, "do i have to create for every message I want to send a new Authorization header? Or is there an option (as with Service Bus Topics) to create a header that can be used for a certain timeframe?"

    With your current approach, the answer is yes. What you can do is create a Shared Access Signature on the queue which will be valid for certain duration and then use that for posting messages to a queue using simple HttpWebRequest/HttpWebResponse.

    SAS, as you descibe I suppose can only be used from within .NET client and not when calling REST services from e.g. C/C++, ...?

    Thanks.

    Monday, May 4, 2015 5:19 PM
  • SAS, as you descibe I suppose can only be used from within .NET client and not when calling REST services from e.g. C/C++, ...?

    Not true. You basically get a SAS token that you can append to your URL (http://storage_account.queue.core.windows.net/myqueue/messages) and then make HTTP calls against that URL. With SAS you don't have to specify Authorization, x-ms-date or x-ms-version headers as they are included in your SAS token.

    Hope this helps.

    Monday, May 4, 2015 5:33 PM