Azure / Azurite

A lightweight server clone of Azure Storage that simulates most of the commands supported by it with minimal dependencies
MIT License
1.74k stars 309 forks source link

403 error when trying to use `UserDelegationKey` #2397

Closed juliusl closed 1 month ago

juliusl commented 1 month ago

Which service(blob, file, queue, table) does this issue concern?

blob

Which version of the Azurite was used?

3.30.0 (VsCode extension)

Where do you get Azurite? (npm, DockerHub, NuGet, Visual Studio Code Extension)

VS Code

What's the Node.js version?

What problem was encountered?

Trying to test GetUserDelegationKeyAsync I get this error:

Azure.RequestFailedException : Server failed to authenticate the request. Make sure the value of the Authorization header is formed correctly including the signature. RequestId:2b581db8-bdf9-4ff5-a5e9-b334aa1faf52 Time:2024-05-09T00:33:06.607Z Status: 403 (Server failed to authenticate the request. Make sure the value of the Authorization header is formed correctly including the signature.) ErrorCode: AuthenticationFailed

Steps to reproduce the issue?

Azure SDK (12.14.1)

var blobServiceClient = new BlobServiceClient(@"DefaultEndpointsProtocol=https;AccountName=devstoreaccount1;AccountKey=Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==;BlobEndpoint=https://localhost:10000/devstoreaccount1;QueueEndpoint=https://localhost:10001/devstoreaccount1;");
var userDelegation = await blobServiceClient.GetUserDelegationKeyAsync(DateTimeOffset.UtcNow, DateTimeOffset.UtcNow.AddMinutes(30), default);

VSCode settings: (cert created w/ dotnet tool)

{
    "azurite.cert": "D:\\storage-test\\cert.pfx",
    "azurite.pwd": "<omitted>",
    "azurite.oauth": "basic",
}

I followed the directions I could find to setup oauth and https for azurite. I tested that I am able to create containers and blobs.

If possible, please provide the debug log using the -d parameter, replacing \<pathtodebuglog> with an appropriate path for your OS, or review the instructions for docker containers:

-d "<pathtodebuglog>"

Please be sure to remove any PII or sensitive information before sharing!
The debug log will log raw request headers and bodies, so that we can replay these against Azurite using REST and create tests to validate resolution.

Have you found a mitigation/solution?

blueww commented 1 month ago

@juliusl

"getUserDelegationKey" only support Oauth (Microsoft Entra ID) authentication. This is same in both product Azure and Azurite. However, you are trying to call it with sharedkey authentication so the failure happen, this is by design in both product Azure and Azurite. See more details in the rest API doc and feature doc: https://learn.microsoft.com/en-us/rest/api/storageservices/get-user-delegation-key#authorization https://learn.microsoft.com/en-us/rest/api/storageservices/create-user-delegation-sas

BTW, to enable Oauth authentication with Azurite, you need to start Azurite with https and Oauth configuration, see https://github.com/Azure/Azurite?tab=readme-ov-file#oauth-configuration And for Oauth, Azurite will do basic authentication, like validating incoming bearer token, checking issuer, audience, expiry. But Azurite will NOT check token signature and permission.

I will close this issue as it's by design. Feel free to contact us again if you need any further assistance on Azurite.

juliusl commented 1 month ago

@blueww

BTW, to enable Oauth authentication with Azurite, you need to start Azurite with https and Oauth configuration, see https://github.com/Azure/Azurite?tab=readme-ov-file#oauth-configuration And for Oauth, Azurite will do basic authentication, like validating incoming bearer token, checking issuer, audience, expiry. But Azurite will NOT check token signature and permission.

Can you give me an example of how to create a test blob client w/ oauth instead of using the emulator connection string?

juliusl commented 1 month ago

I ended up w/ this, is this what you meant?

// See https://aka.ms/new-console-template for more information
using Azure.Core;
using Azure.Storage.Blobs;

Console.WriteLine("Hello, World!");

var client = new BlobServiceClient(new Uri(@"https://localhost:10000/devstoreaccount1"), new TestTokenCredentials());

var key = await client.GetUserDelegationKeyAsync(DateTimeOffset.UtcNow, DateTimeOffset.UtcNow.AddDays(10));

Console.WriteLine(key);

return;

class TestTokenCredentials : TokenCredential
{
    public TestTokenCredentials()
    {
    }

    public override AccessToken GetToken(TokenRequestContext requestContext, CancellationToken cancellationToken)
    {
        return new AccessToken("test", DateTimeOffset.UtcNow.AddDays(1));
    }

    public override ValueTask<AccessToken> GetTokenAsync(TokenRequestContext requestContext, CancellationToken cancellationToken)
    {
        return ValueTask.FromResult(new AccessToken("test", DateTimeOffset.UtcNow.AddDays(1)));
    }
}
blueww commented 1 month ago

I ended up w/ this, is this what you meant?

// See https://aka.ms/new-console-template for more information
using Azure.Core;
using Azure.Storage.Blobs;

Console.WriteLine("Hello, World!");

var client = new BlobServiceClient(new Uri(@"https://localhost:10000/devstoreaccount1"), new TestTokenCredentials());

var key = await client.GetUserDelegationKeyAsync(DateTimeOffset.UtcNow, DateTimeOffset.UtcNow.AddDays(10));

Console.WriteLine(key);

return;

class TestTokenCredentials : TokenCredential
{
    public TestTokenCredentials()
    {
    }

    public override AccessToken GetToken(TokenRequestContext requestContext, CancellationToken cancellationToken)
    {
        return new AccessToken("test", DateTimeOffset.UtcNow.AddDays(1));
    }

    public override ValueTask<AccessToken> GetTokenAsync(TokenRequestContext requestContext, CancellationToken cancellationToken)
    {
        return ValueTask.FromResult(new AccessToken("test", DateTimeOffset.UtcNow.AddDays(1)));
    }
}

We are Azurite owner, but not .net SDK expert, so might not be the best person to give the usage of .net SDK. Here's a .net SDK example for you reference. https://learn.microsoft.com/en-us/azure/storage/blobs/storage-quickstart-blobs-dotnet?tabs=visual-studio%2Cmanaged-identity%2Croles-azure-portal%2Csign-in-visual-studio%2Cidentity-visual-studio&pivots=blob-storage-quickstart-scratch#sign-in-and-connect-your-app-code-to-azure-using-defaultazurecredential

For your above code, it might not work with Azurite, since Azurite will do some basic validation on the token (see details). So use string like "test" as the token won't pass validation in Azurite.

And you must start Azurite with Oauth configuration to support Oauth credential.