Search code examples
c#azureazure-storageazure-blob-storage

Azure Blob returning 403 on upload


I have an azure function that generates a sas key that I later use to upload files to my blob. Here is how I generate the sas key :

CloudBlobContainer container = blobClient.GetContainerReference("sasimagecontainer");
container.CreateIfNotExists();

static string GetContainerSasUri(CloudBlobContainer container)
{
    //Set the expiry time and permissions for the container.
    //In this case no start time is specified, so the shared access signature becomes valid immediately.
    SharedAccessBlobPolicy sasConstraints = new SharedAccessBlobPolicy();
    sasConstraints.SharedAccessStartTime = DateTimeOffset.UtcNow.AddMinutes(-5);
    sasConstraints.SharedAccessExpiryTime = DateTimeOffset.UtcNow.AddMinutes(25);
    sasConstraints.Permissions = SharedAccessBlobPermissions.Write | SharedAccessBlobPermissions.Add | SharedAccessBlobPermissions.Create;

    //Generate the shared access signature on the container, setting the constraints directly on the signature.
    string sasContainerToken = container.GetSharedAccessSignature(sasConstraints);

    //Return the URI string for the container, including the SAS token.
    return container.Uri + sasContainerToken + "&comp=list&restype=container";
}

And then I can call

GetContainerSasUri(container));

to get the sas key. But when I use the following code to call it :

CloudBlockBlob blob = new CloudBlockBlob(thesaskey);
using (var fileStream = File.OpenRead(file))
{
    await blob.UploadFromStreamAsync(fileStream);
}

I keep getting 403 errors. That's all I'm getting from debugging in VS 2017, I'm not sure how can I acquire more information about this problem.

I already looked into most similar threads on SO regarding similar issues and applied possible fixes, like for example the "&comp=list&restype=container" parameter at the end.

// I tried adding SharedAccessBlobPermissions.List to permissions, that didn't work.

// I added literally all the permissions (except None, of course) to check if that might change something - it doesn't. The goal is still to only have permissions to upload.


Solution

  • I was able to reproduce the error and this is how I fixed it:

    You need to pass the SAS to a CloudBlobContainer instead of a CloudBlockBlob. Then use the container to retrieve a blob reference (you may want to use the filename property of your file):

    var container = new CloudBlobContainer(thesaskey);
    var blob = container.GetBlockBlobReference("<yourFileName>");
    await blob.UploadFromFileAsync(@"YOURPATH")
    

    Notice that there is a convenience method UploadFromFileAsync that you can use


    Here is the console application that I used to test it:

    class Program
    {
        static void Main(string[] args)
        {
    
            var connectionString = String.Format("DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1}",
                "<AccountName>",
                "<AccountKey>");
            var storageAccount = CloudStorageAccount.Parse(connectionString);
            var blobClient = storageAccount.CreateCloudBlobClient();
    
    
            var container = blobClient.GetContainerReference("sasimagecontainer");
            container.CreateIfNotExistsAsync().GetAwaiter().GetResult();
    
            var sasUri = GetContainerSasUri(container);
    
    
            var container2 = new CloudBlobContainer(new Uri(sasUri));
            var blob2 = container2.GetBlockBlobReference("blobCreatedViaSAS.txt");
            blob2.UploadFromFileAsync(@"D:\test.txt").GetAwaiter().GetResult();
    
        }
    
        private static string GetContainerSasUri(CloudBlobContainer container)
        {
    
            //Set the expiry time and permissions for the container.
            //In this case no start time is specified, so the shared access signature becomes valid immediately.
            SharedAccessBlobPolicy sasConstraints = new SharedAccessBlobPolicy();
            sasConstraints.SharedAccessExpiryTime = DateTimeOffset.UtcNow.AddHours(24);
            sasConstraints.Permissions = SharedAccessBlobPermissions.List | SharedAccessBlobPermissions.Write |
                                         SharedAccessBlobPermissions.Create |
                                         SharedAccessBlobPermissions.Add | SharedAccessBlobPermissions.Read;
    
            //Generate the shared access signature on the container, setting the constraints directly on the signature.
            var sasContainerToken = container.GetSharedAccessSignature(sasConstraints);
    
            //Return the URI string for the container, including the SAS token.
            return container.Uri + sasContainerToken;
        }
    }