Reputation: 37
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?
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
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