mattdevops
mattdevops

Reputation: 37

Azure Stored access policy, Signature did not match

I receive the error below when trying to access a blob (image) using Sas generated from a policy. Part of MS learn project : https://learn.microsoft.com/en-us/learn/modules/control-access-to-azure-storage-with-sas/6-exercise-use-stored-access-policies

Ran through the exercise twice and still the same result. Any ideas why the signature is an issue?

https://medicalrecords20184.blob.core.windows.net/patient-images/patient-116139-nq8z7f.jpg?sv=2020-08-04&si=patient-images-policy&sr=c&sig=xxxxxxx

AuthenticationFailed Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature. RequestId:328fa4c1-401e-004c-49d2-06e232000000 Time:2022-01-11T10:02:52.3736100Z

Signature did not match. String to sign used was /blob/medicalrecords10150/patient-images patient-images-policy 2020-08-04 c

using System;
using System.Collections.Generic;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Configuration; 

using Azure.Storage.Blobs;
using Azure.Storage.Blobs.Models;
using Azure.Storage.Sas;
using Azure.Storage;

namespace patientrecords.Controllers
{
    [ApiController]
    [Route("api/[controller]")]
    public class PatientRecordsController : ControllerBase
    {
        private readonly ILogger<PatientRecordsController> _logger;
        private IConfiguration _iconfiguration;

        private BlobContainerClient _container;

        private String _storedPolicyID = "patient-images-policy";
 

       public PatientRecordsController(ILogger<PatientRecordsController> logger, IConfiguration iconfiguration)
        {
            _logger = logger;
            _iconfiguration = iconfiguration; 
            _container = new BlobContainerClient(
                _iconfiguration.GetValue<string>("StorageAccount:ConnectionString"),
                _iconfiguration.GetValue<string>("StorageAccount:Container")
            );
            CreateStoredAccessPolicy();
        }

        // GET PatientRecord
        [HttpGet]
        public IEnumerable<PatientRecord> Get()
        {
            List<PatientRecord> records = new List<PatientRecord>();

            foreach (BlobItem blobItem in _container.GetBlobs())
            {
                BlobClient blob = _container.GetBlobClient(blobItem.Name);
                var patient = new PatientRecord { name=blob.Name, imageURI=blob.Uri.ToString() };
                records.Add(patient);
            }

            return records;
        }

        // GET PatientRecord/patient-nnnnnn
        [HttpGet("{Name}")]
        public PatientRecord Get(string name)
        {
            BlobClient blob = _container.GetBlobClient(name);
            return new PatientRecord { name=blob.Name, imageURI=blob.Uri.AbsoluteUri };
        }


         // GET PatientRecord/patient-nnnnnn/secure
        [HttpGet("{Name}/{secure}")]
        public PatientRecord Get(string name, string flag)
        {
            BlobClient blob = _container.GetBlobClient(name);
            return new PatientRecord { name=blob.Name, imageURI=blob.Uri.AbsoluteUri, sasToken=GetBlobSas() };
        }
        // Build a SAS token for the given blob
        private string GetBlobSas(BlobClient blob)
        {
            // Create a user SAS that only allows reading for a minute
            BlobSasBuilder sas = new BlobSasBuilder 
            {
                BlobContainerName = blob.BlobContainerName,
                BlobName = blob.Name,
                Resource = "b",
                ExpiresOn = DateTimeOffset.UtcNow.AddMinutes(1)
            };
            // Allow read access
            sas.SetPermissions(BlobSasPermissions.Read);

            // Use the shared key to access the blob
            var storageSharedKeyCredential = new StorageSharedKeyCredential(
                _iconfiguration.GetValue<string>("StorageAccount:AccountName"),
                _iconfiguration.GetValue<string>("StorageAccount:AccountKey")
            );

            return '?' + sas.ToSasQueryParameters(storageSharedKeyCredential).ToString();
        }

        // Use a stored access policy for the SAS
        private void CreateStoredAccessPolicy()
        {
            // Create a stored access policy for our blobs
            BlobSignedIdentifier identifier = new BlobSignedIdentifier
            {
                Id = _storedPolicyID,
                AccessPolicy = new BlobAccessPolicy
                {
                    //ExpiresOn = DateTimeOffset.UtcNow.AddHours(1),
                    Permissions = "r"
                }
            };

            _container.SetAccessPolicy(permissions: new BlobSignedIdentifier[] { identifier });
        }


        // Build a SAS token for the given blob
        private string GetBlobSas()
        {
            // Create a user SAS that only allows reading for a minute
            BlobSasBuilder sas = new BlobSasBuilder 
            {
                Identifier = _storedPolicyID
            };

            // Use the shared key to access the blob
            var storageSharedKeyCredential = new StorageSharedKeyCredential(
                _iconfiguration.GetValue<string>("StorageAccount:AccountName"),
                _iconfiguration.GetValue<string>("StorageAccount:AccountKey")
            );

            return '?' + sas.ToSasQueryParameters(storageSharedKeyCredential).ToString();
        }

    }



}

Upvotes: 0

Views: 686

Answers (1)

Gaurav Mantri
Gaurav Mantri

Reputation: 136196

I believe you are getting this error is because you have not specified the blob container name in your GetBlobSas() method. Because the blob container name is omitted, the SAS token is computed for $root blob container. Since the SAS token is computed for $root blob container and you are using it with another blob container, you are getting this authorization failed error.

Another issue I noticed is that you have not included expiry in your SAS token. It is not there in your access policy as well as when you get the SAS token using the access policy.

Please try with the following code:

// Build a SAS token for the given blob
 private string GetBlobSas()
 {
     // Create a user SAS that only allows reading for a minute
     BlobSasBuilder sas = new BlobSasBuilder 
     {
         Identifier = _storedPolicyID,
         ExpiresOn = DateTimeOffset.UtcNow.AddHours(1),
         BlobContainerName = _iconfiguration.GetValue<string>("StorageAccount:Container")
     };

     // Use the shared key to access the blob
     var storageSharedKeyCredential = new StorageSharedKeyCredential(
         _iconfiguration.GetValue<string>("StorageAccount:AccountName"),
         _iconfiguration.GetValue<string>("StorageAccount:AccountKey")
     );

     return '?' + sas.ToSasQueryParameters(storageSharedKeyCredential).ToString();
 }

The SAS token you will get from above will expire in 1 hour from the time it was created.

Upvotes: 1

Related Questions