2
votes

I'm trying to create a File Share via REST API but I'm getting this error

AuthenticationFailed Server failed to authenticate the request. Make sure the value of > > > Authorization header is formed correctly including the signature. RequestId:aba10b5f-001a-0026-49cb-51d887000000 Time:2017-10-30T22:04:13.9907093ZThe MAC > signature found in the HTTP request > > > 'U8UvWw4KO0fXAk21p/fuXhfqpDdgK7OZn29r5JQ1x4E=' is not the same as any computed > signature. Server used following string to sign: 'PUT

This is my code:

static void CreatFileShare()
    {
        string requestMethod = "PUT";
        string urlPath = strShareName + "?restype=share";
        string urlPathResource = "restype:share";

        String canonicalizedResource = String.Format("/{0}/{2}\n{1}", StorageAccountName, urlPathResource, /*strShareName*/ "MFS2");
        try
        {
            HttpWebRequest request = GetWebRequest(requestMethod, urlPath, canonicalizedResource, "CreateShare");
            using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
            {
                Console.WriteLine("Response status code: " + response.StatusCode + ".  Successfully Create the share \"" + strShareName + "\".");
            }
        }
        catch (WebException ex)
        {
            ThrowWebException(ex);
        }
    }

static HttpWebRequest GetWebRequest(string requestMethod, string urlPath, String canonicalizedResource, string MethodType)
    {
        HttpWebRequest request = null;
        try
        {
            const string type = "file";
            const string msVersion = "2017-04-17";
            String dateInRfc1123Format = DateTime.UtcNow.ToString("R", CultureInfo.InvariantCulture);
            String canonicalizedHeaders = "";

            //canonicalizedHeaders = String.Format("x-ms-date:{0}\nx-ms-version:{1}", dateInRfc1123Format, msVersion);
            canonicalizedHeaders = String.Format("x-ms-date:{0}\nx-ms-version:{1}\n", dateInRfc1123Format, msVersion);
            if (MethodType == "CreateFile")
            {
                canonicalizedHeaders = String.Format("x-ms-content-length:1024\nx-ms-date:{0}\nx-ms-type:file\nx-ms-version:{1}", dateInRfc1123Format, msVersion);
            }

            String stringToSign = "";


            //stringToSign = String.Format("{0}\n\n\n\n\n\n\n\n\n\n\n\n{1}\n{2}", requestMethod, canonicalizedHeaders, canonicalizedResource);
            stringToSign = String.Format("{0}\n\n\n\n\n\n\n\n\n\n\n\n{1}{2}", requestMethod, canonicalizedHeaders, canonicalizedResource);

            String authorizationHeader = CreateAuthorizationHeader(stringToSign);

            Uri uri = new Uri(FileEndPoint + urlPath);
            request = (HttpWebRequest)WebRequest.Create(uri);
            if (requestMethod != "Get")
            {
                request.ContentLength = 0;
            }

            request.Method = requestMethod;
            request.Headers.Add("x-ms-date", dateInRfc1123Format);
            request.Headers.Add("x-ms-version", msVersion);
            request.Headers.Add("Authorization", authorizationHeader);
            request.Headers.Add("Accept-Charset", "UTF-8");
            request.Accept = "application/atom+xml,application/xml";
            if (MethodType == "CreateFile")
            {
                request.Headers.Add("x-ms-content-length", "1024");
                request.Headers.Add("x-ms-type", type);

            }
        }
        catch (Exception ex)
        {
            throw ex;
        }

        return request;
    }

I'm using the HMAC-SHA256 algorithm within CreateAuthorizationHeader method

My application also has logic to retrieve the File shares and Directories/Files inside a storage account and it's working ok. The problem comes at the moment I want to create a File, File share or share snapshot.

Any help would be greatly appreciated!!

1
Few things: 1) Can you edit your question and include the complete error message? 2) Can you include the output of stringToSign value that you're computing? 3) Can you include code for CreateAuthorizationHeader method? and 4) Is there a reason why you're not using Azure Storage SDK and implementing REST API directly?Gaurav Mantri
@GauravMantri I took a look at the Azure Storage SDK and now I can do what I needed. Thanks!!Aldo Saucedo

1 Answers

1
votes

For Create Share the request would be:

PUT https://{your-storage-accountname}.file.core.windows.net/{share-name}?restype=share

Request Headers:  
x-ms-version: 2017-04-17 
x-ms-date: <date>  
Authorization: SharedKey {your-storage-accountname}:{shared-key-signature-string}  

The canonicalized headers string would be:

x-ms-date:Wed, 01 Nov 2017 05:53:50 GMT\nx-ms-version:2017-04-17\n

The Canonicalized Resource string would be:

/{your-account-name}/{your-share-name}\nrestype:share

While for Create File, the request would be:

PUT https://{your-storage-accountname}.file.core.windows.net/{share-name}/{file}

Request Headers:  
x-ms-version: 2017-04-17 
x-ms-date: <date>  
x-ms-content-length: 1024 //This header specifies the maximum size for the file, up to 1 TB.
Authorization: SharedKey {your-storage-accountname}:{shared-key-signature-string}  

The canonicalized headers string would be:

x-ms-content-length:1024\nx-ms-date:Wed, 01 Nov 2017 06:03:57 GMT\nx-ms-type:file\nx-ms-version:2017-04-17\n

The Canonicalized Resource string would be:

/{your-account-name}/{your-share-name}/{your-file}
//e.g. /brucchstorage/myshare1/helloworld.txt

For your code, you need to modify the parameters urlPath and canonicalizedResource under your CreatFileShare method to support creating the file. Also, you need to append a new-line character (\n) to the canonicalizedHeaders parameter under your GetWebRequest method for the MethodType equals CreateFile.

Additionally, the common cause for this issue dues to the generating for the CanonicalizedResource and CanonicalizedHeaders. I would recommend you refer to Authentication for the Azure Storage Services for a better understanding of them. Also, you could leverage fiddler to capture the network traces and compare the string to sign from the error response with your local value to narrow this issue.

As Gaurav Mantri commented that you could leverage the Azure Storage Client Library for .NET to achieve your purpose in a simple way. More details, you could refer to here.