0

we are facing an exception while generating the SAS Token using GetUserDelegationKey, Here is the exception that we are getting on concurrent requests.

System.ObjectDisposedException: Cannot access a closed Stream.
   at System.IO.MemoryStream.Write(ReadOnlySpan`1 buffer)
   at System.IO.StreamWriter.Flush(Boolean flushStream, Boolean flushEncoder)
   at System.IO.StreamWriter.Dispose(Boolean disposing)
   at System.Xml.XmlTextWriter.Close()
   at Azure.Core.XmlWriterContent.Dispose()
   at Azure.Core.Pipeline.HttpClientTransport.PipelineRequest.Dispose()
   at Azure.Core.HttpMessage.Dispose()
   at Azure.Storage.Blobs.ServiceRestClient.GetUserDelegationKey(KeyInfo keyInfo, Nullable`1 timeout, CancellationToken cancellationToken)
   at Azure.Storage.Blobs.BlobServiceClient.GetUserDelegationKeyInternal(Nullable`1 startsOn, DateTimeOffset expiresOn, Boolean async, CancellationToken cancellationToken)
   at Azure.Storage.Blobs.BlobServiceClient.GetUserDelegationKey(Nullable`1 startsOn, DateTimeOffset expiresOn, CancellationToken cancellationToken)
   at service.mediastorage.DefsultCredntialStorageService.GetUrlWithAccessToken(String url, Double expiredInHours)
   at service.services.VideoService.Convert(Video video) in /home/vsts/work/Source/service.services/VideoService.cs:line 456
   at System.Linq.Enumerable.SelectListIterator`2.ToList()
   at service.services.VideoService.GetVideosByPaginationaAsync(VideoFilterQueryParams filterParameters, LoggedInUserInfo loggedInUserInfo) in /home/vsts/work/Source/service.services/VideoService.cs:line 175
   at service.api.Controllers.VideoController.GetVideosByPaginationAsync(VideoFilterQueryParams videoFilterQueryParameters) in /home/vsts/work/Source/service.api/Controllers/VideoController.cs:line 216

The following code is using to generate sastoken

        public  string GetUrlWithAccessToken(string url, double expiredInHours = 0)
        {
            if (string.IsNullOrEmpty(url)) return null;
            var uri = new Uri(url);

            var blobClient = new BlobClient(uri, GetDefaultCredentials());
            var blobServiceClient = GetBlobServiceClient(_amsSettings.StorageEndPointUrl);

            UserDelegationKey userDelegationKey =  blobServiceClient.GetUserDelegationKey(DateTimeOffset.UtcNow,
                                                                               DateTimeOffset.UtcNow.AddHours(1));
            string sasTokenUrl = GetBlobUrlWithAccessToken(userDelegationKey, blobClient, url, expiredInHours);
            return sasTokenUrl;
        }
        
         private string GetBlobUrlWithAccessToken(UserDelegationKey userDelegationKey, BlobClient blobClient,string url,double expiredInHours)
        {
            // Create a SAS token
            BlobSasBuilder sasBuilder = new BlobSasBuilder()
            {
                BlobContainerName = blobClient.GetParentBlobContainerClient().Name,
                BlobName = blobClient.Name,
                Resource = "b"
            };

          
            sasBuilder.ExpiresOn = DateTimeOffset.UtcNow.AddHours(expiredInHours);
            sasBuilder.SetPermissions(BlobSasPermissions.Read);

            // Add the SAS token to the container URI.
            BlobUriBuilder blobUriBuilder = new BlobUriBuilder(blobClient.Uri)
            {
                // Specify the user delegation key.
                Sas = sasBuilder.ToSasQueryParameters(userDelegationKey,
                                                      blobClient.AccountName)
            };
            var sasToken = blobUriBuilder.Sas.ToString();
            return url + "?" + sasToken;
        }

Can anyone help me regarding this.

Edit:

We are using managed identity and some requests failing when we do load test but some of them success.

Thanks

cva
  • 99
  • 9

1 Answers1

0

Can you please try with this code generate SAS Token

private static string GetSharedAccessSignature(
           string accountName,
           string accountkey,
           string blobContainer,
           string blobName,
           DateTimeOffset sharedAccessStartTime,
           DateTimeOffset sharedAccessExpiryTime)
    {
        var canonicalNameFormat = $"/blob/{accountName}/{blobContainer}/{blobName}";
        var st = sharedAccessStartTime.UtcDateTime.ToString("yyyy-MM-ddTHH:mm:ssZ");
        var se = sharedAccessExpiryTime.UtcDateTime.ToString("yyyy-MM-ddTHH:mm:ssZ");
        var sasVersion = "2016-05-31";
    
        string stringToSign = string.Format("{0}\n{1}\n{2}\n{3}\n{4}\n{5}\n{6}\n{7}\n{8}\n{9}\n{10}\n{11}\n{12}", new object[]
        {
            "r",
            st,
            se,
            canonicalNameFormat,
            string.Empty,
            string.Empty,
            string.Empty,
            sasVersion,
            string.Empty,
            string.Empty,
            string.Empty,
            string.Empty,
            string.Empty
        });
    
        var sas = GetHash(stringToSign, accountkey);
    
        var credentials =
            $"?sv={sasVersion}&sr=b&sig={UrlEncoder.Default.Encode(sas)}&st={UrlEncoder.Default.Encode(st)}&se={UrlEncoder.Default.Encode(se)}&sp=r";
    
        string blobUri = $"https://{accountName}.blob.core.windows.net/{blobContainer}/{blobName}";
        return blobUri + credentials;
    }
    
    private static string GetHash(string stringToSign, string key)
    {
        byte[] keyValue = Convert.FromBase64String(key);
    
        using (HMACSHA256 hmac = new HMACSHA256(keyValue))
        {
            return Convert.ToBase64String(hmac.ComputeHash(Encoding.UTF8.GetBytes(stringToSign)));
        }
    }

For more details refer this SO Thread:

ShrutiJoshi-MT
  • 1,622
  • 1
  • 4
  • 9
  • 1
    OP wants to create a [`User Delegation SAS Token`](https://learn.microsoft.com/en-us/rest/api/storageservices/create-user-delegation-sas). The code you mentioned in your answer creates a [`Service SAS Token`](https://learn.microsoft.com/en-us/rest/api/storageservices/create-service-sas). – Gaurav Mantri Nov 09 '21 at 10:46
  • yes, wants to create User Delegation SAS Token, since we are using ManagedIdentity and latest sdk version Azure.Storage.Blobs=12.9.1 – cva Nov 09 '21 at 11:30
  • Please refer this document: https://www.codewithadam.com/Azure/generating-sas-token-azure-managed-identity-User-Delegation/ – ShrutiJoshi-MT Nov 09 '21 at 11:58
  • its same as my code @ShrutiJoshi-MT – cva Nov 09 '21 at 13:00