Search code examples
azureazure-storageazure-storage-files

shareSasBuilder doesn't work when filename has special characters


I need to allow users to download specific files stored on an Azure File Share. It works fine as long as the filename contains no special characters but fails with a AuthenticationFailed error if it contains any special characters (such as space).

<Error>
<Code>AuthenticationFailed</Code>
<Message>
Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature. RequestId:19654741-801a-0014-1b04-9197c9000000 Time:2020-09-22T17:20:44.1980779Z
</Message>
<AuthenticationErrorDetail>
Signature did not match. String to sign used was r 2020-09-22T19:20:42Z /file/depotsracq/cegep/BA/ZOOM 2.pdf 2019-07-07
</AuthenticationErrorDetail>
</Error>

Here's the method that returns the Uri. I'm pretty sure that it has to do with the encoding of the special characters. In ShareSasBuilder, I pass the filename without encoding (file.Path) but the URL needs the special characters to be encoded. I guess Azure is expecting the special characters to be encoded differently.

    public Uri getFileUri(string filePath)
    {
        ShareDirectoryClient directory = shareClient.GetDirectoryClient(Path.GetDirectoryName(filePath));
        ShareFileClient file = directory.GetFileClient(Path.GetFileName(filePath));

        if (file.Exists())
        {
            var shareSasBuilder = new ShareSasBuilder
            {
                ShareName = directory.ShareName,
                FilePath = file.Path,
                ExpiresOn = DateTime.UtcNow.AddHours(+2)
            };

            shareSasBuilder.SetPermissions(ShareFileSasPermissions.Read);

            SasQueryParameters sasQueryParameters = shareSasBuilder.ToSasQueryParameters(sharedKeyCredential);

            UriBuilder fullUri = new UriBuilder(file.Uri)
            { 
                 Query = sasQueryParameters.ToString()
            };

            return fullUri.Uri;
        }
        else
        {
            return null;
        }
    }

Solution

  • Please make sure you're using the latest version of azure file share package: Azure.Storage.Files.Shares, version 12.4.0.

    I tested it at my side with file name contains special chars like white-space or @ etc. It returns a valid url with sastoken and it can be used to access the file successfully. The sample code is below:

           string conn_str = "DefaultEndpointsProtocol=https;AccountName=xxx;AccountKey=xx;EndpointSuffix=core.windows.net";
            
            var sharedKeyCredential = new StorageSharedKeyCredential("xxx", "xxx");
    
            ShareServiceClient client = new ShareServiceClient(conn_str);
            var shareClient = client.GetShareClient("aaa");
    
            ShareDirectoryClient directory = shareClient.GetDirectoryClient("bbb");
    
            //use file name contains special chars like @
            ShareFileClient file = directory.GetFileClient("foo@@.txt");
    
            //or use the file name contains white-space
            //ShareFileClient file = directory.GetFileClient("foo test.txt");
    
            if (file.Exists())
            {
                var shareSasBuilder = new ShareSasBuilder
                {
                    ShareName = directory.ShareName,
                    FilePath = file.Path,
                    ExpiresOn = DateTime.UtcNow.AddHours(+2)
                };
    
                shareSasBuilder.SetPermissions(ShareFileSasPermissions.Read);
    
                SasQueryParameters sasQueryParameters = shareSasBuilder.ToSasQueryParameters(sharedKeyCredential);
    
                UriBuilder fullUri = new UriBuilder(file.Uri)
                {
                    Query = sasQueryParameters.ToString()
                };
    
                return fullUri.Uri;
            }
    

    Please let me know if you still have any issues.