Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SAS download returns 403 #2412

Open
danjohnso opened this issue Jun 11, 2024 · 12 comments
Open

SAS download returns 403 #2412

danjohnso opened this issue Jun 11, 2024 · 12 comments
Assignees
Labels
blob-storage bug Something isn't working

Comments

@danjohnso
Copy link

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

Blob

Which version of the Azurite was used?

Tested in 3.28.0 from Visual Studio initially, tried upgrading to 3.30.0 with VS Code as well

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

VS Code and Visual Studio 2022

What's the Node.js version?

20.10.0

What problem was encountered?

When trying to download file with a SAS token url, I get a 403 back from Azurite. Connecting to real storage account returns file as expected.

Steps to reproduce the issue?

Tried azurite versions from Visual Studio and VS Code (version info above). Using oauth, https and fixed file location. Flags like so:

--location D:\azurite --oauth basic --cert D:\code\app\.cert\127-cert.pem --key D:\code\app\.cert\127-key.pem --skipApiVersionCheck -d D:\azurite\debug.log

Certificate is valid and I am able to use Azure Storage Explorer to connect and view the files in the instance

Using the Azure.Storage.Blobs SDK version 12.20.0, I have code like this:

UserDelegationKey key = await _blobServiceClient.GetUserDelegationKeyAsync(DateTimeOffset.UtcNow, DateTimeOffset.UtcNow.AddMinutes(5));
BlobSasBuilder sasBuilder = new()
{
    BlobContainerName = containerName,
    BlobName = fileName,
    Resource = "b",
    StartsOn = DateTimeOffset.UtcNow,
    ExpiresOn = DateTimeOffset.UtcNow.AddMinutes(5)
};

sasBuilder.SetPermissions(BlobSasPermissions.Read);

string link = $"{_blobServiceUri}{containerName}/{fileName}?{sasBuilder.ToSasQueryParameters(key, _options.AccountName)}";

Generates a link that looks like this:

https://127.0.0.1:10000/devstoreaccount1/0cd6b12f-2c13-4953-9b13-33fa412d9733/test.png?skt=2024-06-11T16%3A02%3A10Z&ske=2024-06-11T16%3A07%3A10Z&sks=b&skv=2023-11-03&sv=2024-05-04&st=2024-06-11T16%3A02%3A12Z&se=2024-06-11T16%3A07%3A12Z&sr=b&sp=r&sig=lbKCvP0XQ4avTPVi%2FPIea8h3SByi6NBFgm8PqjF436Y%3D

When connected to Azurite, I get a 403 back. Connected to a real storage account, the file downloads as expected (confirmed in an incognito browser window).

I attached the debug.log, looks like it fails on validating the UDK?

azurite-debug.log

Have you found a mitigation/solution?

No, nothing I have done locally seems to work.

@blueww blueww self-assigned this Jun 12, 2024
@blueww blueww added bug Something isn't working blob-storage labels Jun 12, 2024
@blueww
Copy link
Member

blueww commented Jun 12, 2024

@danjohnso

Thanks for reporting this issue!
From the debug log, the error is signature calculated from Azurite code is not aligned with the signature in the SAS.

I can repro it.
I have looked into the stringToSign of Azurite and the one on real Azure server, they have same structure (except account name). The delegation key is also correct per my testing.
Not sure why the signature not match.

I will need more time to debug into SDK code to see what's the real stringTosign SDK use. And compare it with Azurite Code generated one.

@blueww
Copy link
Member

blueww commented Jun 12, 2024

@EmmaZhu

Could you please help to look at the user delegation SAS failure?
Thanks!

@EmmaZhu
Copy link
Collaborator

EmmaZhu commented Jun 12, 2024

Hi @danjohnso

Could you share how you get the _blobServiceClient instance? Service side token credentials may not work for Azurite.

@danjohnso
Copy link
Author

_blobServiceClient = new BlobServiceClient(_options.ServiceUri, new DefaultAzureCredential());

ServiceUri is "https://127.0.0.1:10000/devstoreaccount1/" for Azurite, real connection is "https://ACCOUNT_NAME.blob.core.windows.net/"

@danjohnso
Copy link
Author

Did a little more testing, maybe this is an issue with the SDK....
If I use Azure Storage Explorer, I can generate the token and it works. This is the example generated url:

https://127.0.0.1:10000/devstoreaccount1/0cd6b12f-2c13-4953-9b13-33fa412d9733/test2.png?sv=2018-03-28&st=2024-06-12T14%3A54%3A49Z&se=2024-06-13T14%3A54%3A49Z&sr=b&sp=r&sig=LXc787p4kHXJ8sw%2FaBblbHRLCA38Brw%2BFBDu9rqcLm8%3D

I notice there are less querystring params in this generated URL as compared to the SDK generated one.

@EmmaZhu
Copy link
Collaborator

EmmaZhu commented Jun 12, 2024

Hi @danjohnso ,

The URL you generated by Azure Storage Explorer seems generated by storage key credential instead of OAuth. It doesn't include delegation SAS required query values.

@danjohnso
Copy link
Author

Is there any chance of this getting fixed in the near future?

@EmmaZhu
Copy link
Collaborator

EmmaZhu commented Sep 12, 2024

Hi @danjohnso ,

Is this line of code to try to get user delegation key from Azure Storage Service:
UserDelegationKey key = await _blobServiceClient.GetUserDelegationKeyAsync(DateTimeOffset.UtcNow, DateTimeOffset.UtcNow.AddMinutes(5)); ?

Azurite uses different base key to sign user delegation key with Azure Storage Service, the user delegation key gotten from Azure doesn't work with Azurite.

Could you try with get user delegation key against Azurite?

@danjohnso
Copy link
Author

danjohnso commented Sep 12, 2024 via email

@EmmaZhu
Copy link
Collaborator

EmmaZhu commented Sep 12, 2024

Hi @danjohnso ,

I just saw your code:
_blobServiceClient = new BlobServiceClient(_options.ServiceUri, new DefaultAzureCredential());,

The DefaultAzureCredential class would only work with Azure Storage Service, because it needs to first get a token string from Azure Service , then use the token string to send request to Azure Storage Service. Azurite itself cannot support the step to get a token with DefaultAzureCredential, it only supports to handling requests authenticated with the token string. I was just guessing that you may be using credentials gotten from Azure Storage Service.

I used following code to test Azurite, and the uploading and downloading works fine:

    const token = '< A Token >';
    const serviceClient = new BlobServiceClient(
      baseURL,
      newPipeline(new SimpleTokenCredential(token), {
        retryOptions: { maxTries: 1 },
      })
    );

    const containerName: string = getUniqueName("1container-with-dash");
    const containerClient = serviceClient.getContainerClient(containerName);
    await containerClient.create();

    const startTime = new Date();
    startTime.setHours(startTime.getHours() - 1);
    const expiryTime = new Date();
    expiryTime.setDate(expiryTime.getDate() + 1);

    const userDelegationKey = await serviceClient.getUserDelegationKey(startTime, expiryTime);

    const sasExpirytime = new Date();
    sasExpirytime.setHours(sasExpirytime.getHours() + 1);

    const containerSAS = generateBlobSASQueryParameters(
      {
        blobName: 'test',
        containerName: containerName,
        expiresOn: sasExpirytime,
        permissions: ContainerSASPermissions.parse("rwd"),
      },
      userDelegationKey,
      "devstoreaccount1"
    );

    const containerClientWithSAS = new ContainerClient(
      `${serviceClient.url}/${containerName}?${containerSAS}`,
      newPipeline(new AnonymousCredential())
    );
    const blobClient = await containerClientWithSAS.getBlockBlobClient("test");
    const data = "Test Data";
    await blobClient.upload(data, data.length);
    const downloadResult = await blobClient.download();
    downloadResult;

Could you have a try with the above code?

@yysushi
Copy link

yysushi commented Sep 19, 2024

Hi @EmmaZhu

I'm also having signature mismatch issue. actually I created my client using DefaultAzureCredential.

could you describe how you prepared the token for azurite? I tried some approaches.. but couldn't get it to work...

 const token = '< A Token >';

thank you.

@yysushi
Copy link

yysushi commented Sep 19, 2024

Hi @EmmaZhu

I'm also having signature mismatch issue. actually I created my client using DefaultAzureCredential.

could you describe how you prepared the token for azurite? I tried some approaches.. but couldn't get it to work...

 const token = '< A Token >';

thank you.

oh, I made it by referring to one test case. so, never mind my comment..
looks like I should have generated JTW token with server's key file.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
blob-storage bug Something isn't working
Projects
None yet
Development

No branches or pull requests

4 participants