Azure / azure-sdk-for-net

This repository is for active development of the Azure SDK for .NET. For consumers of the SDK we recommend visiting our public developer docs at https://learn.microsoft.com/dotnet/azure/ or our versioned developer docs at https://azure.github.io/azure-sdk-for-net.
MIT License
5.48k stars 4.81k forks source link

[BUG] Uploading Azure blob using Customer Provided key failing with Status: 403 (This request is not authorized to perform this operation using this permission.) ErrorCode: AuthorizationPermissionMismatch #13600

Closed samruddhi-khairnar closed 4 years ago

samruddhi-khairnar commented 4 years ago

Describe the bug Referred Azure document - https://docs.microsoft.com/en-us/azure/storage/blobs/storage-blob-customer-provided-key I am using above link to upload blob into my storage account using CustomerProvidedKey. And its failing with :

This request is not authorized to perform this operation using this permission. RequestId:ac6dd815-901e-0005-6919-5f3a89000000 Time:2020-07-21T04:42:46.7612266Z Status: 403 (This request is not authorized to perform this operation using this permission.) ErrorCode: AuthorizationPermissionMismatch Headers: Server: Windows-Azure-Blob/1.0,Microsoft-HTTPAPI/2.0 x-ms-request-id: ac6dd815-901e-0005-6919-5f3a89000000 x-ms-client-request-id: ac3537df-1be1-43fb-9df7-d441dfe6e44d x-ms-version: 2019-12-12 x-ms-error-code: AuthorizationPermissionMismatch Date: Tue, 21 Jul 2020 04:42:46 GMT Content-Length: 279 Content-Type: application/xml

I am passing below key as CustomerProvidedKey : SHA256 sha256Hash = SHA256.Create(); byte[] key = sha256Hash.ComputeHash(Encoding.UTF8.GetBytes(randomString));

Expected behavior If the code has no issues, blob should get uploaded

Actual behavior (include Exception or Stack Trace) Failure in blob upload

Environment: M30868971HTDF:new_dir samruddhi.khairnar$ dotnet --info .NET Core SDK (reflecting any global.json): Version: 3.1.302 Commit: 41faccf259

Runtime Environment: OS Name: Mac OS X OS Version: 10.15 OS Platform: Darwin RID: osx.10.15-x64 Base Path: /usr/local/share/dotnet/sdk/3.1.302/

Host (useful for support): Version: 3.1.6 Commit: 3acd9b0cd1

.NET Core SDKs installed: 3.1.302 [/usr/local/share/dotnet/sdk]

.NET Core runtimes installed: Microsoft.AspNetCore.App 3.1.6 [/usr/local/share/dotnet/shared/Microsoft.AspNetCore.App] Microsoft.NETCore.App 3.1.6 [/usr/local/share/dotnet/shared/Microsoft.NETCore.App]

ghost commented 4 years ago

Thanks for the feedback! We are routing this to the appropriate team for follow-up. cc @xgithubtriage.

amnguye commented 4 years ago

Hi,

AuthorizationPermissionMismatch error usually pops up when it's not grabbing the Token correctly from the credentials you provided. Since you're using DefaultAzureCredential to grab your credentials using AAD auth, which kind of auth are you using (e.g. Environment variable, managed identity) https://docs.microsoft.com/en-us/dotnet/api/azure.identity.defaultazurecredential?view=azure-dotnet

I was able to also run this code using a connection string and creating my own token, if you wanted other ways to authenticate.

async static Task UploadBlobWithClientKey(
            string accountName,
            string connectionString,
            string containerName,
            string blobName,
            Stream data,
            byte[] key)
        {
            const string blobServiceEndpointSuffix = ".blob.core.windows.net";
            Uri accountUri = new Uri("https://" + accountName + blobServiceEndpointSuffix);

            // Specify the customer-provided key on the options for the client.
            BlobClientOptions options = new BlobClientOptions()
            {
                CustomerProvidedKey = new CustomerProvidedKey(key)
            };
            // Create a client object for the Blob service, including options.
            BlobServiceClient serviceClient = new BlobServiceClient(connectionString, options);

            // Create a client object for the container.
            // The container client retains the credential and client options.
            BlobContainerClient containerClient = serviceClient.GetBlobContainerClient(containerName);

            // Create a new block blob client object.
            // The blob client retains the credential and client options.
            BlobClient blobClient = containerClient.GetBlobClient(blobName);

            try
            {
                // Create the container if it does not exist.
                await containerClient.CreateIfNotExistsAsync();

                // Upload the data using the customer-provided key.
                await blobClient.UploadAsync(data);
            }
            catch (RequestFailedException e)
            {
                Console.WriteLine(e.Message);
                Console.ReadLine();
                throw;
            }
        }
async static Task UploadBlobWithClientKey(
            string accountName,
            string connectionString,
            string containerName,
            string blobName,
            Stream data,
            byte[] key)
        {
            const string blobServiceEndpointSuffix = ".blob.core.windows.net";
            Uri accountUri = new Uri("https://" + accountName + blobServiceEndpointSuffix);

            // Specify the customer-provided key on the options for the client.
            BlobClientOptions options = new BlobClientOptions()
            {
                CustomerProvidedKey = new CustomerProvidedKey(key)
            };

            TokenCredential token =
                new ClientSecretCredential(
                    tenantId,
                    clientId,
                    clientSecret);
            // Create a client object for the Blob service, including options.
            BlobServiceClient serviceClient = new BlobServiceClient(accountUri,
                token, options);

            // Create a client object for the container.
            // The container client retains the credential and client options.
            BlobContainerClient containerClient = serviceClient.GetBlobContainerClient(containerName);

            // Create a new block blob client object.
            // The blob client retains the credential and client options.
            BlobClient blobClient = containerClient.GetBlobClient(blobName);

            try
            {
                // Create the container if it does not exist.
                await containerClient.CreateIfNotExistsAsync();

                // Upload the data using the customer-provided key.
                await blobClient.UploadAsync(data);
            }
            catch (RequestFailedException e)
            {
                Console.WriteLine(e.Message);
                Console.ReadLine();
                throw;
            }
        }
samruddhi-khairnar commented 4 years ago

Thanks @amnguye. I tried using connection string it worked, the blob got uploaded using CPK. But I tried using ClientSecretCredential by providing those 3 parameters, it again failed with the same error : Status: 403 (This request is not authorized to perform this operation using this permission.) ErrorCode: AuthorizationPermissionMismatch

Can you please help me in understanding why is this behaviour ?

amnguye commented 4 years ago

Looks like there's an error with the credentials you're providing. It could be that the credentials you are providing are incorrect or you have not given your AAD application or identity access to the storage account you are trying to upload a blob to or your AAD identity does not have write permissions.

https://docs.microsoft.com/en-us/azure/storage/common/storage-auth-aad-msi

amishra-dev commented 4 years ago

please reactivate if you are still facing the issue