Get Azure Storage to Return blob URL when listing storage container contents - azure

I'm trying to use a service principal to access and list the contents of an Azure storage container using PowerShell. I've been able to get a token for the service principal and use that to access the storage account but when I run this command
$iwrParams = #{
'Uri' = 'https://myaccount.blob.core.windows.net/mycontainer?restype=container&comp=list'
'UseBasicParsing' = $true
'ContentType' = 'application/xml'
'Headers' = #{
'Authorization' = "Bearer $($token.access_token)"
'x-ms-version' = '2017-11-09'
}
}
Invoke-WebRequest #iwrParams
I get a return from this but the return xml content never shows the URL for each returned blob. If you look at the return at https://learn.microsoft.com/en-us/rest/api/storageservices/enumerating-blob-resources#list-blobs-and-snapshots it shows that for each blob it should return a Name, Url and various other properties. When I run the code above I get everything but the Url.
Now the really interesting thing is if I change the container access to anonymous public and run this code, I get the Url returned as expected.
$iwrParams = #{
'Uri' = 'https://myaccount.blob.core.windows.net/mycontainer?comp=list'
'UseBasicParsing' = $true
'ContentType' = 'application/xml'
}
Invoke-WebRequest #iwrParams
The issue honestly seems to be having to include restype=container when accessing with any sort of authentication.
My question is does anyone know a way to get the URL for each blob returned when not using anonymous access to list container contents?
I'd like to do this without resorting to the Az modules.

The reason you're not able to see the URL returned in the response is because of the storage REST API version used by your code (2017-11-09). Essentially the Blob URL property was removed from the response starting with REST API version 2013-08-15. From this link:
In version 2013-08-15 and newer, the EnumerationResults element
contains a ServiceEndpoint attribute specifying the blob endpoint, and
a ContainerName field specifying the name of the container. In
previous versions these two attributes were combined together in the
ContainerName field. Also in version 2013-08-15 and newer, the Url
element under Blob has been removed.
Regarding your comment about why you can see the URL property if you list blobs anonymously, this is happening because if no REST API version is specified in the request, Storage Service uses the oldest REST API version to process the request if default version has not been set. From this link:
If an anonymous request to a general-purpose storage account does not
specify the x-ms-version header, and the default version for the
service has not been set using Set Blob Service Properties, then the
service uses the earliest possible version to process the request.
Considering you would want to use Azure AD based authorization, the earliest version you will be able to use is 2017-11-09 thus it will not be possible to get the Blob URL returned in the response body.
One option would be to manually construct the Blob URL by using Blob Container URL and Blob name. Other option would be to use Shared Key Authorization instead of Azure AD authorization and specifying a version earlier than 2013-08-15 for x-ms-version request header in your requests. You will need to manually compute Authorization header value in this case using instructions provided here.

Related

Creating an Azure Blob Container using a SAS

I'm trying to create a new container in a Blob Storage account using the Create Container API.
https://myaccount.blob.core.windows.net/mycontainer?restype=container
I can't get this to work, I'm struggling to get the format of the Authorization header right. Other blob services I've used allow this to be passed as a query parameter.
I have the SAS token, similar to ?sv=2019-12-12&ss=bfqt&srt=sco&sp=rwdlacupx&se=2022-02-01T16:52:59Z&st=2021-02-02T08:52:59Z&spr=https&sig=r4%2B7dlSfSO8kyd8mKawHhXNtRzInq7YI%2FIbqSr1g%2FqE%3D
How do I form the Authorization header correctly to pass this?
Thanks.
To create a blob container by using Create Container rest api, if you're using "sas token", then you don't need to add "Authorization" in the Headers.
Assume you have a correct "sas token", then you the request url should look like this(Note: you should remove the first "?" from the "sas token"):
https://myaccount.blob.core.windows.net/mycontainer?restype=container&your_sas_token(note that remove the first ? from sas token)
And in the Headers, you just need pass x-ms-date and x-ms-version.
Here is the test by using Postman:
By the way, here is the screenshot about how to generate the "sas token" for creating blob container:

Error in calling Azure rest API -The requested URI does not represent any resource on the server

i am calling Azure Rest API to list all blobs in a directory (inside container) throuh informatica cloud using web service transformation.But i am getting error while running the mapping InvalidUriThe requested URI does not represent any resource on the server.
API: https://<account_name>.blob.core.windows.net/training?restype=container&comp=list&prefix=training/Type/Class
Could not reproduce your issue, the REST API - List Blobs works fine on my side.
You could refer to the sample below, make sure you are using it the same as mine.
Note: When you using prefix, you have already used the container name training in the url, don't use it again in the parameter, it should be prefix=Type/Class.
Request URL:
GET https://accountname.blob.core.windows.net/training?restype=container&comp=list&prefix=Type/Class
Request header:
x-ms-version = 2019-12-12
Test in the postman:
My storage structure:

Check if a file exists in azure blob container

I have an azure blob container name "x" and I want to check if a file name "a.jpg" exists in that blob or not and return true or false based on that. It seems easy but there isn't a clear answer when I google it.
It is clearly mentioned in the document, if you are using c# you can use ExistsAsync method
public async Task<bool> FileExists(string fileName)
{
return await directory.GetBlockBlobReference(fileName).ExistsAsync();
}
You can also use REST Api if you want.
https://learn.microsoft.com/en-us/rest/api/storageservices/get-blob-metadata
A lot more trouble... but works too.
Request The Get Blob Metadata request may be constructed as follows.
HTTPS is recommended. Replace myaccount with the name of your storage
account:
TABLE 1 GET or HEAD Method Request URI HTTP Version
https://myaccount.blob.core.windows.net/mycontainer/myblob?comp=metadata
https://myaccount.blob.core.windows.net/mycontainer/myblob?comp=metadata&snapshot=

Unable to Get/Post Blob on Azure Storage via Rest API in C#

Upon successful consumption of Azure Rest api in c# code. I'm able to create, fetch and fetch list of containers but not blob. While accessing or uploading blobs, this gives permission issue and i.e.,
you are not authorized to perform this request with assigned permission
Progress that i have made so far:
Able to create and fetch the container.
Able to fetch the list of all the containers of storage account.
When tries to Get/Put a blob via below source code it give me error:
This request is not authorized to perform this operation using this permission.
string endPointUri = $"{azureApplicationConfiguration.Resource}/{inpContainerName}/{inpBlobName}";
var request = (HttpWebRequest)WebRequest.Create(endPointUri);
request.Method = HTTPMethod.GET.ToString();
request.Headers.Add("Authorization", $"Bearer {sasToken.access_token}");
request.Headers.Add("x-ms-date", DateTime.UtcNow.ToString("R"));
request.Headers.Add("x-ms-version", "2018-03-28");
request.ProtocolVersion = HttpVersion.Version11;
using (HttpWebResponse resp = (HttpWebResponse)request.GetResponse())
{
Console.WriteLine(resp.StatusCode.ToString());
Console.ReadKey();
}
The most likely answer is that the SAS token you're using to authenticate does not support object level access. You can confirm this by checking if there is a letter o in the Signed Resource Types srt= parameter in your SAS token. Based on the fact you can list and create containers, I'd guess the current value is srt=sc. To be able to perform GET/PUT operations on a blob as well, you'll need to generate a new SAS token that includes object level permissions, which should give you a token containing srt=sco.
In case you aren't aware of it already, there is a .NET Azure Storage SDK available, which provides a layer of abstraction over the REST API and may save you some time in the long run.

Python: Upload a package to Azure using SAS URI

I am using the Microsoft's Hardware dashboard API to automate the submission of my (.CAB) package for signing. I have followed the steps in this documentation: https://learn.microsoft.com/en-us/windows-hardware/drivers/dashboard/create-a-new-submission-for-a-product
The response of new submission contains the SAS(Shared Access Signature) URI
like this: (changed the sig and accnt_name for security)
'''https://accnt_name.blob.core.windows.net/scsjc/cexxxxxxxxxx?sv=2017-04-17&sr=b&sig=xxxxxxxxxxxxxx&se=2019-07-10T18:15:58Z&sp=rwl&rscd=attachment%3B filename%3Dinitial_xxxxxxxx.cab'''
I need to use this SAS URI to upload by package to azure blob storage.
The examples in documentation shows C# or .NET as follows:
string sasUrl =
"https://productingestionbin1.blob.core.windows.net/ingestion/26920f66-
b592-4439-9a9d-fb0f014902ec?sv=2014-02-
14&sr=b&sig=usAN0kNFNnYE2tGQBI%2BARQWejX1Guiz7hdFtRhyK%2Bog%3D&se=2016-
06-17T20:45:51Z&sp=rwl";
Microsoft.WindowsAzure.Storage.Blob.CloudBlockBlob blockBob =
new Microsoft.WindowsAzure.Storage.Blob.CloudBlockBlob(new
System.Uri(sasUrl));
await blockBob.UploadFromStreamAsync(stream);
I want to use the SAS URI obtained from submission resource JSON Response to upload the package.
This link Download file from AZURE BLOB CONTAINER using SAS URI in PYTHON suggests that there is no equivalent method in python and BlockBlobService can be used.
from azure.storage.blob import BlockBlobService
blobservice = BlockBlobService("storage_account",sas_token="?sv=2018-03-
28&ss=bfqt&srt=sco&sp=rwdlacup&se=2019-04-24T10:01:58Z&st=2019-04-
23T02:01:58Z&spr=https&sig=xxxxxxxxx")
blobservice.create_blob_from_path(container_name, local_file_name,
full_path_to_file)
However I am not sure of what is storage_account name and container name from the SAS URI obtained from submission resource.
Also I have created a separate azure storage account and added a new container, blob in it. I have tried passing the new container and storage account name with SAS access token from SAS URI (obtained from submission JSON response micorsoft hardware api) but always get below ERROR
'''
AzureHttpError: Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature. ErrorCode: AuthenticationFailed
AuthenticationFailedServer failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature.
RequestId:5463b7d2-901e-0068-6994-36782e000000
Time:2019-07-09T20:23:04.5760736ZSignature did not match. String to sign used was rwl
2019-07-10T18:15:58Z
/blob/evcertautomation/ev2/initial_1152921504628106590.cab
2017-04-17
attachment; filename=initial_1152921504628106563.cab
'''
Thanks in advance
If you have a blob SAS URI as you post below, you can easily upload a file to the blob in Python with requests.
https://accnt_name.blob.core.windows.net/scsjc/cexxxxxxxxxx?sv=2017-04-17&sr=b&sig=xxxxxxxxxxxxxx&se=2019-07-10T18:15:58Z&sp=rwl&rscd=attachment%3B filename%3Dinitial_xxxxxxxx.cab
First, you must have to inspect the values of parameters se and sp. The se parameter means the expire time of the blob SAS URI, and the sp parameter means the operation permisson of the blob SAS URL like w for Blob Write Permission
So for your blob SAS URL above, you have the blob write permission to upload a file to this blob before the time 2019-07-10T18:15:58Z.
Here is my sample code for uploading via a blob sas uri.
import requests
blob_sas_uri = '<your blob sas uri which must includes `sp=w` and do the write operation before `se`>'
local_file_name = '<your local file name>'
headers = {
'x-ms-blob-type': 'BlockBlob'
}
data = open(local_file_name).read()
r = requests.put(blob_sas_uri, headers=headers, data=data)
print(r.status_code)
If you see the result is 201, it works fine and succeed for uploading.
As reference, there is a similar offical sample Example: Upload a Blob using a Container’s Shared Access Signature which using a wide container permission.
As per the SAS URI you provided: '''https://accnt_name.blob.core.windows.net/scsjc/cexxxxxxxxxx?sv=2017-04-17&sr=b&sig=xxxxxxxxxxxxxx&se=2019-07-10T18:15:58Z&sp=rwl&rscd=attachment%3B filename%3Dinitial_xxxxxxxx.cab'''
The account name should be accnt_name, the container should be scsjc.
So your code should look like below:
from azure.storage.blob import BlockBlobService
storage_account ="accnt_name"
token="?sv=2018-03-
28&ss=bfqt&srt=sco&sp=rwdlacup&se=2019-04-24T10:01:58Z&st=2019-04-
23T02:01:58Z&spr=https&sig=xxxxxxxxx"
container="scsjc"
blobservice = BlockBlobService(storage_account,sas_token=token)
blobservice.create_blob_from_path(container, local_file_name,
full_path_to_file)

Resources