Specifying SAS Token Authorization header with Azure REST API - azure

There are tons of posts on SO about how the Authorization header is not needed when using a SAS token as part of the URI. Those posts are correct, and the following code works:
Dim oRequest
Dim sURL
Dim SASToken
SASToken = "sv=2021-10-04&ss=btqf&srt=sco&st=2023-01-10T14%3A23%3A49Z&se=2024-01-10T14%3A23%3A00Z&sp=rwdxftlacup&sig=MySigButNotNotMyRealSig%3D"
sURL = "https://myaccount.queue.core.windows.net/myqueue/messages?peekonly=true&numofmessages=32&" & SASToken
Set oRequest = CreateObject("MSXML2.XMLHTTP.6.0")
oRequest.Open "GET", sURL
oRequest.setRequestHeader "x-ms-date", getUTC
oRequest.Send
Wscript.Echo oRequest.Status, oRequest.statusText
Output:
200 OK
However, I have an IoT device that limits the URL length to 288 characters. The shortest I've been able to make my URI with my SAS Token tacked on is 320 characters. Short of making my blobs public, I think my only option is to actually use the Authorization header, but just putting the Sas token in the Authorization header does not work.
Dim oRequest
Dim sURL
Dim SASToken
SASToken = "sv=2021-10-04&ss=btqf&srt=sco&st=2023-01-10T14%3A23%3A49Z&se=2024-01-10T14%3A23%3A00Z&sp=rwdxftlacup&sig=MySigButNotNotMyRealSig%3D"
sURL = "https://myaccount.queue.core.windows.net/myqueue/messages?peekonly=true&numofmessages=32&" & SASToken
Set oRequest = CreateObject("MSXML2.XMLHTTP.6.0")
oRequest.Open "GET", sURL
oRequest.setRequestHeader "x-ms-date", getUTC
oRequest.setRequestHeader "Authorization", "SharedAccessSignature " & SASToken
oRequest.Send
Wscript.Echo oRequest.Status, oRequest.statusText
Output:
400 Authentication information is not given in the correct format.
Check the value of Authorization header.
I have seen some code that generates a SHA256 hash of information and uses that in the header, but my IoT device cannot generate this.

Unfortunately you can't pass a SAS token in authorization header. It will have to be a part of your request URL.
However, there are a few things you can do to reduce your request URL length.
Use Service SAS for the queue instead of Account SAS. That will remove ss=btqf&srt=sco from the SAS token. Instead you will get sr=q.
See if you can omit SAS start date (st) as it is optional. If SAS start date is not included in the SAS token, then the SAS token becomes effective immediately.
Use only the permissions that you need. Right now your SAS token has all permissions. By restricting the permissions to only the required ones, you can further reduce the request URL length. Since you're just peeking at the messages, all you need is read permission (sp=r).
See if you can move your SAS token related parameters in an access policy. That way your SAS token will only have signed version, access policy and the signature parameters.

Related

Generate/retrieve a SAS token programmatically for specific Blob/File under azure storage account via REST API in POSTMAN and then in IBM APP Connect

I have requirement where it has to be done programmatically using POSTMAN REST API, where I have to upload a file/blob to Azure storage account and retrieve the unique URL of the specific file that I have uploaded, and I have to share that URL to third party so that they can view it on browser.
This is what I have done in the POSTMAN
Request:
PUT https://{storage-account-name}.blob.core.windows.net/{container-name}/{file-name}{SAS-token}
Headers:
x-ms-version: 2020-04-08
x-ms-blob-type: BlockBlob
x-mock-response-name: Upload Blob
Body: Attached a file from my local
Response:
I have received 200 code and file is successfully uploaded. However, in the response headers I don't see any URL or unique SAS token that I can share to my third-party client.
I have also tried adding se and sp to sas token, I got the below error
AuthenticationFailed
Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature. RequestId:65282b4e-401e-0050-2337-43ee90000000 Time:2023-02-18T01:20:28.3522177Z
**Signature did not match. String to sign used was r 2023-02-18T09:12:15Z /blob/storage-account-name/container-name/file-name.txt 2021-06-08 b **
Note: We don't want to generate SAS token manually from Azure portal for each file and construct the URL and share it to the client due to high traffic coming in. Once it is successful using POSTMAN. I have to implement the same in IBM App Connect enterprise, ESQL coding*
All the suggestions are much appreciated. Thank you in advance.
Retrieve the unique URL of the specific file that I have uploaded programmatically and share that URL with third party so that they can view it on browser.
In addition to the se and sp parameters, the following parameters are required to construct the correct SAS URL:
signed version (sv)
signed resource (sr)
signature
Your error message says that the signature does not match the rest of the URL. Signature a hash-based message authentication code (HMAC) that you compute over the string-to-sign and key by using the SHA256 algorithm, and then encode by using Base64 encoding
You can find how to construct the string-to-sign and signature depending on the version on this documentation page.
Postman has a built-in JavaScript library that can help you to calculate HMAC:
CryptoJS.HmacSHA1("string-to-sign", "key").toString()

Karate API Test - Bearer error="invalid_token", error_description="The audience <number> is invalid"

Postman headers I'm using secret keys to generate an access token that I will use to authenticate for an API that I call. The issue is that I'm getting the error:
status code was: 401, expected: 200
WWW-Authenticate: Bearer error="invalid_token", error_description="The audience value is invalid"
This is how I call the API
Given url `https://login.microsoftonline.com/tenant_id/oauth2/token`
And form field grant_type = `client_credentials`
And form field client_id = `value`
And form field client_secret = `value`
When method post
Then status 200
match response.access_token != null
def access_token = response.access_token
print access_token
Given header Authorization = 'Bearer ' + access_token
Given url 'url'
And header accept = `plain/text`
And header 'X-Mimic-User' = `confidential`
When method GET
Then status 200
I'm expecting to the authenticated to the API with the generated access token.
So it appears your error may be related to the Authorization header, although the error description is hard to decipher, possibly scope related? I would list the URL first, not the header, unless you are re-using it, and want to configure the value for subsequent requests. Another way of setting the Bearer token is:
And match response.access_token == '#present'
* def oauthToken = `Bearer ${response.access_token}`
But really the most important thing is for you to check your request, including headers and compare it between Karate and Postman to see what is different.
From what I see in the error description, the first API call made towards your auth provider is returning a 200 with an access token. but the second call you are making to your application server seems to be failing to see the audience value in your access token.
I doubt you are using the same client credentials input (client_id, client_secret) in your postman and karate setup. Make sure they are the same.
I would also confirm if the access token received is having the aud parameter by checking it in https://jwt.io or any other tool you trust to decode your access token JWT. for the sake of experimentation do the same for the access token you got from postman as well.
Ideally, these configurations are very internal to your application and identity team and may not be directly related to karate. The other teams mentioned should be the ones best to guide you.

Azure Copy Blob REST API is throwing AuthenticationFailed with SAS token

I am trying to call Azure Copy Blob API from postman. I have passed below headers and hit the request but I am getting "AuthenticationFailed" error.
I am sure, I might have given wrong header values or missed some required headers. Can some please help me what am I missing.
Here is the request:
Method: PUT
URL: https://accountname.blob.core.windows.net/containername/SAMPLE_FILE.CSV
Headers:
Authorization = SHARED ACCESS SIGNATURE:?sv=2020-08-04&ss=bfqt&srt=sco&sp=rwdlacupitfx&se=2023-05-30T06:52:46Z&st=2022-05-31T22:52:46Z&spr=https,http&sig=lP1fdHkWabckHlMFOrUsAWyVu6zxxJwNX4l%2B6a0WAmE%3D
x-ms-version = 2015-04-05
x-ms-copy-source = https://accountname.blob.core.windows.net/containername/SAMPLE_FILE.CSV
x-ms-date = 2022-06-13T18:51:28.5001104Z
Response Received:
Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature.
RequestId:aa820193-601e-0037-5959-7f7a5b000000
The reason you are getting this error is because you are using incorrect authorization header.
When you use SAS token, you would need to use SAS URL as the base URL for your copy operation and do not include authorization header as SAS token already contains the authorization information.
Do try with the following PUT URL and you will not get the authorization failed error (assuming your SAS token is valid):
Method: PUT URL:
https://accountname.blob.core.windows.net/containername/SAMPLE_FILE.CSV?sv=2020-08-04&ss=bfqt&srt=sco&sp=rwdlacupitfx&se=2023-05-30T06:52:46Z&st=2022-05-31T22:52:46Z&spr=https,http&sig=lP1fdHkWabckHlMFOrUsAWyVu6zxxJwNX4l%2B6a0WAmE%3D

Azure Blob Storage with SAS Token

I'm trying to upload a file to Azure Storage Account as Blob and I have a client provided by this "github.com/Azure/azure-storage-blob-go/azblob" package. As I saw in documentation there should be possibility to communicate with Storage using SAS Token creating anonymous credential with
credential := azblob.NewAnonymousCredential()
po := azblob.PipelineOptions{
Log: pipeline.LogOptions{
Log: func(s pipeline.LogLevel, m string) {
log.Tracef("pipeline message: %s", m)
},
ShouldLog: func(level pipeline.LogLevel) bool {
return level <= pipeline.LogError
},
},
}
pipeline := azblob.NewPipeline(credential, po)
However, I don't see an option to pass SAS Token which I receive from other service after I ask for access.
I also tried do it 'manually' using Azure Storage Account REST API, so my URL was like https://servicename.blob.core.windows.net/containerID/BlobID?sasToken... but all I get was 400, 411 and 501 HTTP codes depending on request header.
For example with
req.Header.Add("Accept", "*/*")
req.Header.Add("Accept-Language", "en-US,en;q=0.5 --compressed")
req.Header.Add("Accept-Encoding", "gzip, deflate, br")
req.Header.Add("content-type", "application/octet-stream")
req.Header.Add("x-ms-version", "2019-02-02")
req.Header.Add("x-ms-blob-type", "BlockBlob")
req.Header.Add("x-ms-client-request-id", "someID")
req.Header.Add("Connection", "keep-alive")
req.Header.Add("Content-Length", "512000")
req.Header.Add("Transfer-Encoding", "gzip, chunked, deflate")
I receive 400 code with
<?xml version="1.0" encoding="utf-8"?>
<Error>
<Code>MissingRequiredHeader</Code>
<Message>
An HTTP header that's mandatory for this request is not specified.
RequestId:someId
Time:2020-02-14T13:47:58.8383371Z
</Message>
<HeaderName>x-ms-original-content-length</HeaderName>
</Error>
Adding x-ms-original-content-length header changes nothing.
The funny fact is that it only happens when I try it in Go code. When I tried any REST Client it was working with these headers.
Summarizing, my need is to put a file into Azure Storage Account as a blob and the second solution which should simply work, does not work, and first one is not completed because I don't see the way to pass SAS Token. What am I missing?
So in the 1st case the problem was that SAS token is passed nowhere in this package. It should be added to URL later on during url creation like:
URL, err := url.Parse(blobURL + "/" + containerName + "/" + blobName + "?token as query"
And in the second case everything was about Content-Length which is not changeable from Header side. It's automatically set during http.NewRequest(...) but it must be one of following types *bytes.Buffer, *bytes.Reader or *strings.Reader. Otherwise it's 0. However http.NewRequest(...) accepts io.Reader as body, so it will compile with everything implementing io.Reader interface like *os.File but it will not set Content-Length which is required in case of Azure Storage Account. When I switched to one of three given types I listed above it started working.

How to get accesstoken via code using Azure Oauth 2.0

The situation:
I have successfully get the code parameter from returning url via
https://login.microsoftonline.com/{tenant}/oauth2/authorize?client_id=XXXX-XXXX-XXXX&response_type=code&redirect_uri=http%3A%2F%2Flocalhost%2F&response_mode=query
now I need to get accesstoken for getting user info, I post parameters to this url:
https://login.microsoftonline.com/{tenant}/oauth2/v2.0/token
2 ways I had tried:
1.
var nvc = new NameValueCollection();
nvc.Add("grant_type", "authorization_code");
nvc.Add("client_id", "xxx-xxxx-xxxx");
nvc.Add("code", code.Value);
nvc.Add("redirect_uri", "http://localhost/");
nvc.Add("client_secret", "XXXXXXXXXXXXXX=");
nvc.Add("resource", "https://graph.microsoft.com/");
nvc.Add("scope", "email");
client.Headers.Add("Content-Type", "application/x-www-form-urlencoded");
var response = Encoding.UTF8.GetString(client.UploadValues(url,"POST", nvc));
2.
var xx = new StringContent("grant_type=authorization_code"+
"&client_id=xxx-xxxx-xxxx" +
"&code=codeXXXXXXXX" +
...
"&resource=https://graph.microsoft.com/",
Encoding.UTF8,
"application/x-www-form-urlencoded");
client.PostAsync(url,xx);
All of them returned a error 400, and I got a error message :
{
"error":"invalid_request",
"error_description":"AADSTS90014: The request body must contain the following parameter: 'grant_type'.\r\nTrace ID: 207dd940-78ff-46ba-bec0-00821c850f00\r\nCorrelation ID: 803afff4-3917-4030-a19b-b5629e1faf97\r\nTimestamp: 2017-05-19 02:51:19Z",
"error_codes":[
90014
],
"timestamp":"2017-05-19 02:51:19Z",
"trace_id":"207dd940-78ff-46ba-bec0-00821c850f00",
"correlation_id":"803afff4-3917-4030-a19b-b5629e1faf97"
}
First, you were mixing the Azure AD endpoint with Azure AD V2.0 endpoint. And from the error message, you didn't specify the grant_type parameter. Please make sure to send this parameter in the request. And the send request should also return the different error like The 'resource' request parameter is not supported.
If you were using the Azure AD endpoint, you can refer this link for the request to acquire the token. And for the Azure AD V2.0 you can refer v2.0 Protocols - OAuth 2.0 Authorization Code Flow.
If you still have the problem, please share the exact code you were developing and let us know which endpoint you were developing.
As Fei Xue mentioned, you should not mix the endpoints. You can use:
https://login.microsoftonline.com/{tenant}/oauth2/token
to get the access token.
Thank you guys.
I finally fellow this article and successfully got the access token, logged user info. The point to successfully get the access token is to give right parameters, the following block shows an example of correct parameters.
public static string clientId = "9fb8ee69-xxxx-xxxx-xxxx-xxxxxxx";
public static string authority = "https://login.windows.net/9c80d42c-yyyy-yyyy-yyyy-yyyyyyyyy/oauth2/authorize";
public static string returnUri = "https://kuozuinotification.azurewebsites.net/.auth/login/aad/callback"; << my issue caused by here
private const string resource = "https://graph.windows.net/";

Resources