question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

[QUERY] GetUserDelegationKeyAsync() authentication failure for Service Client created using connection string

See original GitHub issue

Query/Question I am writing a Blazor WASM App and using Azure AD B2C to authenticate. I wish to give each authenticated user access to their own blob container (based on their UserID). I have successfully authenticated users and can connect to blob storage using a connection string, from the server layer.

However, when I run the following

                key = await _blobServiceClient.GetUserDelegationKeyAsync(
                        DateTimeOffset.UtcNow,
                        DateTimeOffset.UtcNow.AddDays(1),
                        cancellationToken)
                    .ConfigureAwait(false);

I get the following error message:

Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature.
RequestId:952e0446-c01e-000d-1131-299d64000000
Time:2020-05-13T14:19:19.3831245Z
Status: 403 (Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature.)
ErrorCode: AuthenticationFailed

Headers:
Server: Windows-Azure-Blob/1.0,Microsoft-HTTPAPI/2.0
x-ms-request-id: 952e0446-c01e-000d-1131-299d64000000
x-ms-client-request-id: a3a45f58-0d85-43a1-bf1d-80c01b945d77
x-ms-version: 2019-07-07
x-ms-error-code: AuthenticationFailed
Date: Wed, 13 May 2020 14:19:18 GMT
Content-Length: 421
Content-Type: application/xml

Using Fiddler 4, I can see the authorisation appears in the outgoing header, and the same _blobServiceClient can successfully be used to create/list containers and get properties etc. so I’m confident the connection string is good.

I’ve spent a couple of days but hit a dead end. I’ve read there’s a difference between an account connection (which is presumably what the connection string gives me?) but suggestions to call GetClient are deprecated, and instead, the closest I can see is _blobServiceClient.GetBlobContainerClient() which returns a BlobContainerClient which does not expose GetUserDelegationKeyAsync().

The plan is to pass the key to a BlobSasBuilder to grant read-only access to the user’s container so that the Blazor WASM client can retrieve resources directly. Whilst writes will stream through the server layer for validation, throttling, etc. However, I can’t get that far as I can’t get the UserDelegationKey.

The examples show the creation of a new BlobServiceClient each time, without using a connection string and instead use a DefaultAzureCredential. I don’t want to use that approach if I can avoid it because setting up a user with global access seems like a lot of extra work compared to just using the connection string. However, is that the recommended approach, and is GetUserDelegationKeyAsync not allowed when you are authenticating with the connection string (in which case the error message could do with being a touch more informative as I can’t find anywhere that states that is the case).

I am slowly grasping the concepts but many examples show deprecated code and the whole things seems fiendishly overcomplicated for what should be a relatively simple task - providing a read-only URI to an authenticated user’s personal container that prevents write access or access to other containers. (I also will provide a URI to a read-only global container for all users).

Any help would be appreciated, and apologies if I’m obviously doing something dumb.

Environment:

  • Azure.Storage.Blobs 12.4.2
  • Visual Studio 16.5.3
  • Host
.NET Core SDK (reflecting any global.json):
 Version:   3.1.201
 Commit:    b1768b4ae7

Runtime Environment:
 OS Name:     Windows
 OS Version:  10.0.18363
 OS Platform: Windows
 RID:         win10-x64
 Base Path:   C:\Program Files\dotnet\sdk\3.1.201\

Host (useful for support):
  Version: 3.1.3
  Commit:  4a9f85e9f8

.NET Core SDKs installed:
  3.1.201 [C:\Program Files\dotnet\sdk]

.NET Core runtimes installed:
  Microsoft.AspNetCore.All 2.1.17 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All]
  Microsoft.AspNetCore.App 2.1.17 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 3.1.3 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.NETCore.App 2.1.17 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 3.1.3 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.WindowsDesktop.App 3.1.3 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Comments:5 (2 by maintainers)

github_iconTop GitHub Comments

6reactions
seanmcc-msftcommented, May 13, 2020

Hi @thargy, Get User Delegation Key doesn’t work with connection string or Shared Key auth, which explains why you are getting a 403.

If you’d like to create a read-only, time-bounds and container-restricted URL, I’d recommend regular SAS.

using Azure.Storage;
using Azure.Storage.Blobs;
using Azure.Storage.Blobs.Specialized;
using Azure.Storage.Sas;
using System;
using System.Net;
using System.Threading.Tasks;

namespace ConsoleApp3
{
    class Program
    {
        static async Task Main(string[] args)
        {
            string accountName = "";
            string accountKey = "";
            Uri serviceUri = new Uri("");
            StorageSharedKeyCredential sharedKeyCredential = new StorageSharedKeyCredential(accountName, accountKey);
            BlobServiceClient blobServiceClient = new BlobServiceClient(serviceUri, sharedKeyCredential);
            BlobContainerClient containerClient = blobServiceClient.GetBlobContainerClient("mycontainer998");
            PageBlobClient pageBlobClient = containerClient.GetPageBlobClient("mypageblob");
            try
            {
                await containerClient.CreateAsync();
                await pageBlobClient.CreateAsync(1024);

                BlobSasBuilder blobSasBuilder = new BlobSasBuilder()
                {
                    BlobContainerName = containerClient.Name,
                    StartsOn = DateTimeOffset.UtcNow.AddMinutes(-5),
                    ExpiresOn = DateTimeOffset.UtcNow.AddDays(1),
                    IPRange = new SasIPRange(IPAddress.None, IPAddress.None),
                    Protocol = SasProtocol.None
                };
                blobSasBuilder.SetPermissions(BlobSasPermissions.Read);
                BlobUriBuilder sasUriBuilder = new BlobUriBuilder(containerClient.Uri)
                {
                    Query = blobSasBuilder.ToSasQueryParameters(sharedKeyCredential).ToString()
                };

                // Now we have the container SAS Uri we can use to contruct blob client for blobs in the container.
                Uri containerSasUri = sasUriBuilder.ToUri();

                BlobUriBuilder blobUriBuilder = new BlobUriBuilder(containerSasUri)
                {
                    BlobName = pageBlobClient.Name
                };

                PageBlobClient sasPageBlob = new PageBlobClient(blobUriBuilder.ToUri());

                await sasPageBlob.GetPropertiesAsync();
            }
            finally
            {
                await containerClient.DeleteAsync();
            }
        }
    }
}
1reaction
thargycommented, May 15, 2020

Thank you @seanmcc-msft, I’ll give that a go when I get back to that area of functionality.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Unable to access blobServiceClient. ...
I am trying to access blob in Azure. I can access it using the blobClient.DownloadToAsync call as shown in the GetAsync method below....
Read more >
AzureStorage Blob Server failed to authenticate ...
I got this error when using Azurite on my local development machine and I misconfigured the connection string to be used by the...
Read more >
Azure SQL Database "Login failed for user" in application ...
When switching our API to connect to an Azure database via a new contained user, we had to change our connection string to...
Read more >
Class BlobServiceClient | Azure SDK for Net
A connection string includes the authentication information required for your application to access data in an Azure Storage account at runtime.
Read more >
Interacting with Azure Blob Storage using AAD credentials
It gives you an easy way to handle Azure AD authentication from your code. The way this library works is that it first...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found