"Signature did not match..." when upload blob to Azure Storage with Fine-uploader - azure

I've a ton of SO post about this error, but I checked everything and still don't find why Azure Blob Storage keep failing authenticate my upload request.
I use Fine-Uploader to generate the request :
var uploaderInstance = $('#baz-fine-uploader').fineUploaderAzure({
template: 'qq-template-manual-trigger',
debug: true,
request: {
containerUrl: 'https://{MYACCOUNT}.blob.core.windows.net/client1',
endpoint: 'https://{MYACCOUNT}.blob.core.windows.net/client1'
},
// for Azure
signature: {
endpoint: "/api/upload/sas"
},
uploadSuccess: {
endpoint: "/api/upload/success"
},
cors: {
//all requests are expected to be cross-domain requests
expected:true
}
});
I generate the SAS URI with the Azure SDK, following what is recommended by Fine-uploader :
public string GetBlobSAS(string bloburi, string method)
{
try
{
var credentials = new StorageCredentials(STORAGE_ACCOUNT_NAME, STORAGE_ACCOUNT_KEY);
CloudBlockBlob blob = new CloudBlockBlob(new Uri(bloburi), credentials);
var sas = blob.GetSharedAccessSignature(new SharedAccessBlobPolicy()
{
Permissions = SharedAccessBlobPermissions.Read | SharedAccessBlobPermissions.Write | SharedAccessBlobPermissions.Create,
SharedAccessExpiryTime = DateTime.UtcNow.AddMinutes(15)
});
return string.Format(CultureInfo.InvariantCulture, "{0}{1}", bloburi, sas);
}
catch (Exception ex)
{
Debug.WriteLine(ex);
throw ex;
}
}
I created a CORS access policy through the Azure portal, and for test purpose, I set "everything" allowed, especially the "Allowed-Origin" field to "*", as I'm testing from my locahost :
Finally, Fine-uploader ask me for the SAS, fetch it and BOUM, the server answers :
OPTIONS https://{MYACCOUNT}.blob.core.windows.net/client1/5f89f3ae-2d10-4e4e-8f3f-25d…QAY40QjKGoJcDsHolt8KXjB86chaTWg0f4t4%3D&se=2016-12-20T14%3A34%3A58Z&sp=rcw 403 (Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature.)
XMLHttpRequest cannot load https://{MYACCOUNT}.blob.core.windows.net/client1/5f89f3ae-2d10-4e4e-8f3f-25d…QAY40QjKGoJcDsHolt8KXjB86chaTWg0f4t4%3D&se=2016-12-20T14%3A34%3A58Z&sp=rcw. Response for preflight has invalid HTTP status code 403
The server response is
<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:71041c4f-0001-00cf-69cc-5aa7de000000 Time:2016-12-20T14:21:35.7541369Z
</Message>
<AuthenticationErrorDetail>
Signature did not match. String to sign used was rcw 2016-12-20T14:34:58Z /blob/{MYACCOUNT}/client1/5f89f3ae-2d10-4e4e-8f3f-25d7b4760965.PNG 2015-12-11
</AuthenticationErrorDetail>
</Error>
Really don't know what else I can do now..
According to whatever SO post, I also tried to add a "&comp=list&restype=container" at the end of my SAS URI, tried several combinations with that, none of them worked...
Any ideas??

Related

Mobile app performing an HTTP Post to Azure Function using Bearer Token and Function Key returns Unauthorized

I'm using a mobile app and am receiving an Unauthorized response when attempting to post to an Azure Function and providing a function key.
Error:
StatusCode: 401, ReasonPhrase: 'Unauthorized'
Code:
let postToAsync (baseAddress:string) (resource:string) (payload:Object) =
async {
let tokenSource = new CancellationTokenSource(TimeSpan(0,0,30));
let token = tokenSource.Token;
try
let tokens = resource.Split("?code=")
let functionKey = tokens.[1]
use client = httpClient baseAddress
client.DefaultRequestHeaders.Add("x-functions-key", functionKey)
client.DefaultRequestHeaders.Accept.Add(MediaTypeWithQualityHeaderValue("application/json"))
let json = JsonConvert.SerializeObject(payload)
let content = new StringContent(json, Encoding.UTF8, "application/json")
let! response = client.PostAsync(resource.Replace($"?code={functionKey}",""), content, token) |> Async.AwaitTask
Debug.WriteLine $"\n\n{baseAddress}{resource}\nSuccess: {response.IsSuccessStatusCode}\n\n"
return response
with ex -> ...
} |> Async.StartAsTask
Note:
My Azure Function's AuthorizationLevel is set to Function.
I can call the function successfully when I publish it manually from Visual Studio.
However, when I deploy the function using Pulumi, I receive an Unauthorized response. I believe this is because Pulumi constrains me to add access policies for each Function App.
Versioning:
<TargetFramework>net6.0</TargetFramework>
<AzureFunctionsVersion>v4</AzureFunctionsVersion>
oauth2/v2.0:
I think the following link provides a clue to why I'm observing the issue. However, I still don't know how to resolve it.
Connectivity
I launched Log Stream and observed that the URL is correct:
Access Control:
Please note that the difference between the Function App that I created without using Pulumi, which lets me post successfully, versus the Function App that was generated using Pulumi, is an Access Policy per Function App with Pulumi.
public static class AccessPolicies
{
public static void Build(string policyName, string functionName, Dictionary<string, CustomResource> registry)
{
var resourceGroup = registry[nameof(ResourceGroup)] as ResourceGroup;
var keyVault = registry[nameof(KeyVault)] as KeyVault;
var functionApp = registry[functionName] as FunctionApp;
var result = new AccessPolicy(policyName, new AccessPolicyArgs {
KeyVaultId = keyVault.Id,
TenantId = TenantId.Value,
ObjectId = functionApp.Identity.Apply(v => v.PrincipalId ?? "11111111-1111-1111-1111-111111111111"),
KeyPermissions = new[] { "Get", },
SecretPermissions = new[] { "Get", },
});
registry.Add($"{policyName}-{functionName}", result);
}
}
}
I tried to reproduce the same in my environment via Postman and got below results:
I have one function app with http function named srifunction like below:
I generated one bearer token with same scope as you like below:
POST https://login.microsoftonline.com/<tenantID>/oauth2/v2.0/token
grant_type:client_credentials
client_id: <appID>
client_secret: <secret_value>
scope: https://management.azure.com/.default
Response:
When I used the above token to call function, I got 401 Unauthorized error same as you like below:
POST https://<funcappName>.azurewebsites.net/api/<function_name>
Authorization: Bearer <token>
If you pass function key in token value, you will still get 401 Unauthorized error like below:
POST https://<funcappName>.azurewebsites.net/api/<function_name>
Authorization: Bearer <function key>
To call function using function key, you need to include key value
in x-functions-key header instead of Bearer token.
When I included the above header, I am able to call the function successfully like below:
POST https://<funcappName>.azurewebsites.net/api/<function_name>
x-functions-key: <function key>

how to get informations about operations rest api on azure storage account

i tried to get all operations (Get, Put, Delete)etc.. on a specific storage account but I don't get all information (on which container, on which blob)..
I tried these two api :
1)
https://management.azure.com/subscriptions/XXX/resourceGroups/XXX/providers/Microsoft.Storage/storageAccounts/XXX/providers/microsoft.insights/metrics?metricnames=Transactions&timespan=2022-12-18T02:00:00Z/2022-12-20T02:05:00Z&\$filter=apiname+eq+'*'+and+ResponseType+eq+'*'+&interval=PT24H&aggregation=Total&orderby=Total+desc&api-version=2019-07-01
but I get only the number and the response type
2)
https://management.azure.com//providers/Microsoft.Storage/providers/operations?api-version=2019-07-01
Data layer operations are available on resource log(diagnostics logs).
Refer documentation how to enable logging into log analytics workspace: https://learn.microsoft.com/en-us/azure/storage/blobs/monitor-blob-storage?tabs=azure-portal#collection-and-routing
After turning on logging you can run queries to fetch operation from StorageBlobLogs table.
Use the below params as headers to get rid of un- authorization error while accessing the API
x-ms-date :
x-ms-version :
Authorization : SharedKey storagename: Signature
Authorization is shown in below snippet
Create a storage account and container in Azure
Storage account
Container
code in C# to fetch the Headers of x-ms-date ,
x-ms-version , and Authorization
using (var Req = new HttpRequestMessage(HttpMethod.Get, uri)
{ Content = (requestPayload == null) ? null : new ByteArrayContent(requestPayload) })
{
DateTime now = DateTime.UtcNow;
Req.Headers.Add("x-ms-date", now.ToString("2022-12-26 8:40:16 PM", CultureInfo.InvariantCulture));
Req.Headers.Add("x-ms-version", "2022-09-01");
Req.Headers.Authorization = AzureStorageAuthenticationHelper.GetAuthorizationHeader(
storageAccountName, storageAccountKey, now, Req);
using (HttpResponseMessage Resp = await new HttpClient().SendAsync(Req, cancellationToken))
{
if (Resp.StatusCode == HttpStatusCode.OK)
{
String xmlString = await Resp.Content.ReadAsStringAsync();
XElement x = XElement.Parse(xmlString);
foreach (XElement container in x.Element("Containers").Elements("Container"))
{
Console.WriteLine("Container name = {0}", container.Element("Name").Value);
}
}
}
}
for more information, please check this link

Node.js reading a blob with azure and creating a SAS token

So I am currently writing some code that gets a container and then selects a blob and makes a SAS token. which all currently work but I get a error when I try to open the link.
The error being given is this.
AuthenticationFailed
Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature. RequestId:somethingsomething
The specified signed resource is not allowed for the this resource level
const test = () => {
const keyCredit = new StorageSharedKeyCredential('storageaccount', 'key')
const sasOptions = {
containerName: 'compliance',
blobName: 'swo_compliance.csv',
};
sasOptions.expiresOn = new Date(new Date().valueOf() + 3600 * 1000);
sasOptions.permissions = BlobSASPermissions.parse("r");
const sasToken = generateBlobSASQueryParameters(sasOptions, keyCredit).toString();
console.log(`SAS token for blob container is: url/?${sasToken}`);
return `url/?${sasToken}`;
}
I tried to reproduce the scenario in my system able to download the blob using the sas token
While you returning the return url/?${sasToken}; in your code remove the “/” just give the
the return url?${sasToken};
Example URL : https://StorageName.blob.core.windows.net/test/test.txt?SASToken
I tried in my system able to download blob

Azure DevOps REST API call to Accounts-endpoint retrieves TF400813 error

I'm trying to read all accounts my user is associated with. The Documentation claims that this should be possible by calling:
GET https://app.vssps.visualstudio.com/_apis/accounts?api-version=5.1
Because the docs are kind of confusing it could be that I have to call
GET https://app.vssps.visualstudio.com/_apis/accounts?ownerId={GUID}&api-version=5.1
instead.
I'm using OAuth-Authentication. In order to get it work I created an ASP.NET Core application. I created an app registration in DevOps and I retrieve an OAuth token with the following scopes without any problem:
vso.auditlog
vso.connected_server
vso.dashboards
vso.entitlements
vso.environment_manage
vso.graph
vso.identity
vso.loadtest
vso.machinegroup_manage
vso.memberentitlementmanagement
vso.profile
vso.project
vso.securefiles_read
vso.security_manage
vso.taskgroups_read
vso.tokenadministration
vso.tokens
vso.variablegroups_read
vso.wiki
According to the docs only vso.profile should be necessary for this request.
However the result I receive is always:
HttpRequestException: Response status code does not indicate success: 401 (TF400813: The user '{AZURE_TENANT_ID}\{MY_MAIL_ADDRESS}' is not authorized to access this resource.).
Other requests are working just fine e.g.:
GET https://dev.azure.com/{organization}/{project}/_apis/build/builds?api-version=5.1
The accounts-request is special because it can be sent without setting the context to a specific organisation or project. I guess this the reason for the different results.
EDIT
After trying ot today using the both URLs mentioned above I now get 400 as the response status code. This is a sample Bearer-Token I got after I decoded it:
{
"nameid": "1340eb0b-cabf-476c-a950-a070c34ca367",
"scp": "vso.profile",
"aui": "a2d8bdf0-9406-415a-aa79-bee9e2600c37",
"appid": "e1bea2a2-****-****-****-************",
"iss": "app.vstoken.visualstudio.com",
"aud": "app.vstoken.visualstudio.com",
"nbf": 1587395030,
"exp": 1587398630
}
Here is some simplified C# code I use:
HttpClient client = _clientFactory.CreateClient("DevOps");
var token = await _authHelper.GetTokenAsync(tokenType);
client.DefaultRequestHeaders.Add("Authorization", $"Bearer { token.AccessToken}");
var uri = "https://app.vssps.visualstudio.com/_apis/accounts?api-version = 5.1";
try
{
var response = await client.GetAsync(uri);
response.EnsureSuccessStatusCode();
var content = await response.Content.ReadAsStringAsync();
return content;
}
catch (Exception ex)
{
// ex.Message = Response status code does not indicate success: 400 (Bad Request).
// ...
throw;
}

Azure Blob Rest API with SAS

Im trying to upload file directly from web browser using the Azure storage Rest API and Ajax(actually im using Angular's $http)
I've followed every possible official and custom guides without success.
For starters my CORS is set like this:
var storageAccount = CloudStorageAccount.Parse(StorageConnectionString);
var blobClient = storageAccount.CreateCloudBlobClient();
var blobServiceProperties = blobClient.GetServiceProperties();
blobServiceProperties.Cors = new CorsProperties();
blobServiceProperties.Cors.CorsRules.Add(new CorsRule()
{
AllowedHeaders = new List<string>() { "*" },
AllowedMethods = CorsHttpMethods.Put | CorsHttpMethods.Get | CorsHttpMethods.Head | CorsHttpMethods.Post,
AllowedOrigins = new List<string>() { "*" },
ExposedHeaders = new List<string>() { "*" },
MaxAgeInSeconds = 1800 // 30 minutes
});
blobClient.SetServiceProperties(blobServiceProperties);
At UI level I call my own API that returns the SAS URL like this:
var storageAccount = CloudStorageAccount.Parse(StorageConnectionString);
var blobClient = storageAccount.CreateCloudBlobClient();
var container = blobClient.GetContainerReference("fotosrestaurantes");
var blobPermissions = container.GetPermissions();
blobPermissions.SharedAccessPolicies.Clear();
blobPermissions.SharedAccessPolicies.Add("enviarFotoRestaurante", new SharedAccessBlobPolicy()
{
Permissions = SharedAccessBlobPermissions.Write | SharedAccessBlobPermissions.Read | SharedAccessBlobPermissions.Create | SharedAccessBlobPermissions.Add
SharedAccessExpiryTime = DateTime.UtcNow.AddMinutes(30),
});
container.SetPermissions(blobPermissions);
var sasToken = container.GetSharedAccessSignature(null, "enviarFotoRestaurante");
return Ok(sasToken);
Then im using this Angular Module for uploading the blob: https://github.com/kinstephen/angular-azure-blob-upload
So far so good, but when I try to upload I get this from OPTIONS request (from Chrome's Network tab):
403 Server failed to authenticate the request. Make sure the value of
Authorization header is formed correctly including the signature.
And this from the console:
XMLHttpRequest cannot load 'myAzureHttpLink/fotosrestaurantes/google.jpg?sv=2015-04-05&sr=b&si=enviarFoto&sig=***&se=2016-01-11T14%3A16%3A22Z&sp=w&comp=block&blockid=YmxvY2stMDAwMDAw
Response to preflight request doesn't pass access control check: No
'Access-Control-Allow-Origin' header is present on the requested
resource. Origin 'http://localhost:34090' is therefore not allowed
access. The response had HTTP status code 403.
Now, as far as I could understand from the oficial documentation(most are very breif on thier matter and have lots of links that almost never cover what you really need on them) if I choose to use SAS URL I dont need the authorization header. As Gaurav says here: https://stackoverflow.com/a/33846704/3198372
I've tryed everything, from container SAS to blob SAS but nothing works. As if the CORS configuration and SAS URL just dont work(even if they are there).
Anyone knows where Im wrong?

Resources