1

I'm trying to list the containers in my windows azure storage account. but i'm struck with an exception
"The remote server returned an error: (403) Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature.."

But i have included the signature as per the instructions given, do any one find any mistake in my code ?

private static String SignThis(string StringToSign,string  Key,string  Account)
        {

            String signature = string.Empty;
            byte[] unicodeKey = Convert.FromBase64String(Key);
            using (HMACSHA256 hmacSha256 = new HMACSHA256(unicodeKey))
            {
                Byte[] dataToHmac = System.Text.Encoding.UTF8.GetBytes(StringToSign);
                signature = Convert.ToBase64String(hmacSha256.ComputeHash(dataToHmac));
            }

            String authorizationHeader = String.Format(
                System.Globalization.CultureInfo.InvariantCulture,
                "{0} {1}:{2}",
                "SharedKey",
                Account,
                signature);
            return authorizationHeader;
        }
        static void ListContainers()
        {
            Thread.CurrentThread.CurrentCulture = System.Globalization.CultureInfo.InvariantCulture;
            string Key = @"MyStorageAccountKey";
            string Account = @"MyStorageAccountName";

            DateTime dt = DateTime.UtcNow;

            string dataStr = dt.ToString ("R",System.Globalization.CultureInfo.InvariantCulture);
            string StringToSign = String.Format("GET\n"
                + "\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
                + "x-ms-date:" + dataStr + "\nx-ms-version:2014-02-14\n" // headers
                + "/{0}\ncomp:list", Account);

            string auth = SignThis(StringToSign, Key, Account);
            string method = "GET";
            string urlPath = string.Format ("https://{0}.blob.core.windows.net/?comp=list", Account);
            Uri uri = new Uri(urlPath);
            HttpWebRequest reque = (HttpWebRequest)WebRequest.Create(uri);
            reque.Method = method;
            reque.Headers.Add("Authorization", auth);
            reque.Headers.Add("x-ms-date",dataStr);
            reque.Headers.Add("x-ms-version", "2014-02-14");

            using (HttpWebResponse response = (HttpWebResponse) reque.GetResponse ()) {
                using (StreamReader reader = new StreamReader(response.GetResponseStream()))
                {
                    string text = reader.ReadToEnd();
                }
            }
        }

Edit : String i Used to generate Signature

GET

x-ms-date:Tue, 14 Jul 2015 18:38:16 GMT
x-ms-version:2014-02-14
/MyStorageAccountName/
comp:list

Edit : I received the exception response :

<?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:2fc74ef8-0001-0083-2664-be8850000000
Time:2015-07-14T18:38:18.0831721Z</Message><AuthenticationErrorDetail>The MAC signature found in the HTTP request '5rqWNl2i8kuZF6haCRqFr1S0viOM9eLjz4L/zU6GCsg=' is not the same as any computed signature. Server used following string to sign: 'GET

x-ms-date:Tue, 14 Jul 2015 18:38:16 GMT
x-ms-version:2014-02-14
/MyStorageAccountName/
comp:list'.</AuthenticationErrorDetail></Error>

Final Edit: After making all the changes specified by gauvrav, i found that the storagekey i used was wrong, after replacing the right one, it is working fine.

There may be other changes for this error: please refer this link

Community
  • 1
  • 1
VivekParamasivam
  • 1,086
  • 2
  • 13
  • 23
  • 1
    The error response should include the string-to-sign the Storage service used, so you can use that to validate if you are missing something in your string-to-sign. – Serdar Ozler Jul 14 '15 at 17:46
  • thanks, can you explain how to get the value of "string-to-sign" of the storage service ? – VivekParamasivam Jul 14 '15 at 17:50
  • 1
    What @SerdarOzler-Microsoft means is that if you run your code and have Fiddler running (or checking the error by parsing the response of WebException you get), you will see in the error message the StringToSign used by Server. You can compare that with your StringToSign to see what is not matching. I used this trick to find the problem in your code. – Gaurav Mantri Jul 14 '15 at 17:56

1 Answers1

3

Please change your StringToSign to:

        string StringToSign = String.Format("GET\n"
            + "\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
            + "x-ms-date:" + dataStr + "\nx-ms-version:2014-02-14\n" // headers
            + "/{0}/\ncomp:list", Account);//Notice an extra "/" after "{0}"

It was missing a / after account name placeholder (last line in the code above). Once you do that, you should be able to see the list of containers returned in XML format.

Gaurav Mantri
  • 128,066
  • 12
  • 206
  • 241
  • Thanks for pointing gaurav. i changed it, getting the same error. i guess some other mistake is there ? – VivekParamasivam Jul 14 '15 at 17:57
  • 1
    Hmmm...that's weird. I just tried it and it is working perfectly fine for me. Here's my copy of the code: http://pastebin.com/KusuaqPS. Can you run your code and trace the request/response in Fiddler and share it here? Two other possible reasons for 403 errors are - 1) Incorrect account key 2) Clock on your computer being slow (say off by more than 15 - 20 minutes). Please check for these as well. – Gaurav Mantri Jul 14 '15 at 18:03
  • your response giving a big hope. i have not tried fiddler before, will try it and reply you soon. thanks for the response. – VivekParamasivam Jul 14 '15 at 18:10
  • Should my system time needs to be corrected ? because the "dataStr" variable in the code displays 14 Jul 2015 18:14:18 GMT, but my system time is totally different. I'm trying in fiddler too. – VivekParamasivam Jul 14 '15 at 18:17
  • 1
    :). If you don't have Fiddler, try the code here: http://pastebin.com/VB0cYALU. I have included the code to fetch the error string returned in WebException. Regarding your question, not particularly. The `dataStr` displays the time in GMT which will be different than your computer's date time if you are not in the same time zone. – Gaurav Mantri Jul 14 '15 at 18:20
  • Added the error message i received in the question, please have a look . – VivekParamasivam Jul 14 '15 at 18:30
  • 1
    Thanks. Can you also put the `StringToSign` calculated from your code as well in your question? Please update your question with the latest error message as well so that we can compare both of them together. – Gaurav Mantri Jul 14 '15 at 18:35
  • updated the question with the new response and the string i use for signature – VivekParamasivam Jul 14 '15 at 18:43
  • Gaurav, i found that the storage key i used was wrong, replaced the right key it is working now. Even if i used right key, it would not have worked without making the changes you specified , so accepted your answer as right. – VivekParamasivam Jul 14 '15 at 19:08