question

CollinBrittain-9320 avatar image
0 Votes"
CollinBrittain-9320 asked CollinBrittain-9320 commented

Put Blob from URL AuthenticationFailed. Using Azure Storage SDK and all required headers.

Hello,

I am testing out using the Put Blob from URL operation to copy a photo from my Google Photos account to Azure Blobs. I am getting stuck at authorization of the request. I downloaded the storage-dotnet-rest-api-with-auth repo to give me an example of how to interact with the API, and the provided List operation works fine. However, when I make my own request using the Put Blob from URL operation, I cannot authenticate. I believe I am providing all of the required headers, and it should be in correct canonicalized form because I am using the provided AzureStorageAuthenticationHelper.GetAuthorizationHeader() method.

The request URL:

string containerName = "<containername>";
string blobName = "photo1.jpg";
String uri = string.Format("https://{0}.blob.core.windows.net/{1}/{2}", storageAccountName, containerName, blobName);


My header code:

DateTime now = DateTime.UtcNow;
httpRequestMessage.Headers.Add("x-ms-date", now.ToString("R", CultureInfo.InvariantCulture));
httpRequestMessage.Content.Headers.ContentType = MediaTypeHeaderValue.Parse("image/jpeg");
httpRequestMessage.Headers.Add("x-ms-version", "2020-04-08");
httpRequestMessage.Headers.Add("x-ms-copy-source", "<url>");
httpRequestMessage.Headers.Add("x-ms-blob-type", "BlockBlob");
// If you need any additional headers, add them here before creating
//   the authorization header. 

// Add the authorization header.
httpRequestMessage.Headers.Authorization = AzureStorageAuthenticationHelper.GetAuthorizationHeader(
    storageAccountName, storageAccountKey, now, httpRequestMessage);


The resulting request:

x-ms-date: Sun, 21 Feb 2021 16:00:49 GMT
x-ms-version: 2020-04-08
x-ms-copy-source: <url>
x-ms-blob-type: BlockBlob
Authorization: SharedKey <accountname>:<key>

Content-Type: image/jpeg
Content-Length: 0

https://myaccount.blob.core.windows.net/mycontainer/photo1.jpg


The 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:aea0e156-a01e-0037-3a6a-082086000000
Time:2021-02-21T16:00:48.6817608Z
    </Message>
    <AuthenticationErrorDetail>
        The MAC signature found in the HTTP request '<signature>' is not the same as any computed signature. Server used following string to sign: 
'PUT




image/jpeg






x-ms-blob-type:BlockBlob
x-ms-copy-source:<url>
x-ms-date:Sun, 21 Feb 2021 16:00:49 GMT
x-ms-version:2020-04-08
/myaccount/mycontainer/photo1.jpg'.
    </AuthenticationErrorDetail>
</Error>


I have done a lot of searching and can't find a resolution to this problem. Most related issues are people strugging to get the canonicalized string correct but they aren't using the microsoft-provided method like I am which takes care of that.

What am I missing?

EDIT: If this is not the right place to post this question please redirect me.



azure-blob-storage
· 1
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

@CollinBrittain-9320
Thanks for your question. I am looking into the issue and will provide an update once I have more information available.

0 Votes 0 ·
deherman-MSFT avatar image
1 Vote"
deherman-MSFT answered CollinBrittain-2345 commented

@CollinBrittain-9320
I confirmed with the product team that AzureStorageAuthenticationHelper is out of date and for a different/older .NET SDK.

We highly recommend you use our official Azure Storage .NET SDK instead - Azure.Storage.Blobs. There is also Azure.Storage.DataMovement which already has the copy from a file from url ability you are trying to accomplish.

Here is our sample for how to download a blob using Azure.Storage.Blobs

Hope this helps. Let us know if you have further questions or issues and we will be happy to assist. Also Stack Overflow is another great resource that is actively monitored and responded to.



Please don’t forget to "Accept the answer" and “up-vote” wherever the information provided helps you, this can be beneficial to other community members.

· 1
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

Ok thank you for the information. I will give it go.

0 Votes 0 ·
deherman-MSFT avatar image
0 Votes"
deherman-MSFT answered CollinBrittain-9320 commented

@CollinBrittain-2345
I was able to gather some sample code that you might find helpful. Here’s a sample using the v12 Storage SDK library to copy more than one file to Azure blobs using the SyncCopyFromUrl API:

     // A list of tasks that are currently executing
     List<Task<Response<BlobCopyInfo>>> runningTasks = new List<Task<Response<BlobCopyInfo>>>();
     int maxWorkers = 4;

     // List all the blobs
     string sourceDirectoryName = "a/";
     int prefixSize = sourceDirectoryName.Length-1;
     string destDirectoryName = "c/";
     //List<string> names = new List<string>();
     await foreach (BlobItem blob in container.GetBlobsAsync(prefix: sourceDirectoryName))
     {
         BlobClient destBlob = container.GetBlobClient(destDirectoryName + blob.Name.Substring(prefixSize));
         Task<Response<BlobCopyInfo>> task = destBlob.SyncCopyFromUriAsync(container.GetBlobClient(blob.Name).Uri);
         runningTasks.Add(task);

         // Check if any of our tasks are still busy
         if (runningTasks.Count >= maxWorkers)
         {
             await Task.WhenAny(runningTasks).ConfigureAwait(false);

             // Clear any completed blocks from the task list
             for (int i = 0; i < runningTasks.Count; i++)
             {
                 Task runningTask = runningTasks[i];
                 if (!runningTask.IsCompleted)
                 {
                     continue;
                 }

                 await runningTask.ConfigureAwait(false);
                 runningTasks.RemoveAt(i);
                 i--;
             }
         }
     }
     // Wait for all our tasks
     await Task.WhenAll(runningTasks).ConfigureAwait(false);

     foreach (Task<Response<BlobCopyInfo>> task in runningTasks)
     {
         Assert.AreEqual(task.Result.Value.CopyStatus, CopyStatus.Success);
     }

Also here is a snippet of authenticating with the SDK:

     string accountName = StorageAccountName;
     string accountKey = StorageAccountKey;
     BlobUriBuilder uriBuilder = new BlobUriBuilder()
     {
         AccountName = StorageAccountName,
         BlobContainerName = containerName,
         BlobName = blobName
     };
     Uri serviceUri = uriBuilder.ToUri();

     // Create a SharedKeyCredential that we can use to authenticate
     StorageSharedKeyCredential credential = new StorageSharedKeyCredential(accountName, accountKey);

     // Create a client that can authenticate with a connection string
     BlobServiceClient service = new BlobServiceClient(serviceUri, credential);






· 2
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

Thanks @deherman-MSFT.

Just to be clear, I'm trying to import photos to Blob storage from another website (thus the URL) without having to download to an intermediary storage location. Can this accomplish that, or is it limited to other blobs already in Azure?

0 Votes 0 ·

Okay I tested it out using the source URL from google photos and it works! Thanks so much for the help.

1 Vote 1 ·