30
votes

I am building an Angular 6 application that will be able to make CRUD operation on Azure Blob Storage. I'm however using postman to test requests before implementing them inside the app and copy-pasting the token that I get from Angular for that resource.

When trying to read a file that I have inside the storage for test purposes, I'm getting: <Code>AuthorizationPermissionMismatch</Code> <Message>This request is not authorized to perform this operation using this permission.

  • All in production environment (although developing)
  • Token acquired specifically for storage resource via Oauth
  • Postman has the token strategy as "bearer "
  • Application has "Azure Storage" delegated permissions granted.
  • Both the app and the account I'm acquiring the token are added as "owners" in azure access control IAM
  • My IP is added to CORS settings on the blob storage.
  • StorageV2 (general purpose v2) - Standard - Hot
  • x-ms-version header used is: 2018-03-28 because that's the latest I could find and I just created the storage account.
6
so users need IAM permissions on the blob storage ???Thomas
@Thomas I have no idea mate, I just added it anyway to be sure that's not the reason.SebastianG

6 Answers

78
votes

I found it's not enough for the app and account to be added as owners. I would go into your storage account > IAM > Add role assignment, and add the special permissions for this type of request:

  • Storage Blob Data Contributor
  • Storage Queue Data Contributor
3
votes

Be aware that if you want to apply "STORAGE BLOB DATA XXXX" role at the subscription level it will not work if your subscription has Azure DataBricks namespaces:

If your subscription includes an Azure DataBricks namespace, roles assigned at the subscription scope will be blocked from granting access to blob and queue data.

Source: https://docs.microsoft.com/en-us/azure/storage/common/storage-auth-aad-rbac-portal#determine-resource-scope

2
votes

I've just solved this by changing the resource requested in the GetAccessTokenAsync method from "https://storage.azure.com" to the url of my storage blob as in this snippet:

    public async Task<StorageCredentials> CreateStorageCredentialsAsync()
    {
        var provider = new AzureServiceTokenProvider();
        var token = await provider.GetAccessTokenAsync(AzureStorageContainerUrl);
        var tokenCredential = new TokenCredential(token);
        var storageCredentials = new StorageCredentials(tokenCredential);
        return storageCredentials;
    }

where AzureStorageContainerUrl is set to https://xxxxxxxxx.blob.core.windows.net/

2
votes

Make sure you add the /Y at the end of the command.

1
votes

Used the following to connect using Azure AD to blob storage: This is code uses SDK V11 since V12 still has issues with multi AD accounts See this issue https://github.com/Azure/azure-sdk-for-net/issues/8658 For further reading on V12 and V11 SDK

https://docs.microsoft.com/en-us/azure/storage/blobs/storage-quickstart-blobs-dotnet-legacy

https://docs.microsoft.com/en-us/azure/storage/blobs/storage-quickstart-blobs-dotnet

using Microsoft.Azure.Services.AppAuthentication;
using Microsoft.Azure.Storage.Auth;
using Microsoft.Azure.Storage.Blob;
using Microsoft.Azure.Storage.Queue;

[Fact]
public async Task TestStreamToContainer()
        {
            try
            {
                var accountName = "YourStorageAccountName";
                var containerName = "YourContainerName";
                var blobName = "File1";
                var provider = new AzureServiceTokenProvider();
                var token = await provider.GetAccessTokenAsync($"https://{accountName}.blob.core.windows.net");
                var tokenCredential = new TokenCredential(token);
                var storageCredentials = new StorageCredentials(tokenCredential);

                string containerEndpoint = $"https://{accountName}.blob.core.windows.net";

                var blobClient = new CloudBlobClient(new Uri(containerEndpoint), storageCredentials);
                var containerClient = blobClient.GetContainerReference(containerName);
                var cloudBlob = containerClient.GetBlockBlobReference(blobName);


                string blobContents = "This is a block blob contents.";
                byte[] byteArray = Encoding.ASCII.GetBytes(blobContents);

                using (MemoryStream stream = new MemoryStream(byteArray))
                {
                    await cloudBlob.UploadFromStreamAsync(stream);
                }
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
                Console.ReadLine();
                throw;
            }
        }
0
votes

Make sure to use Storage Blob Data Contributor and NOT Storage Account Contributor where the latter is only for managing the actual Storage Account and not the data in it.