Use PowerShell with OAuth Token for HTTP Azure Function - azure

I have an Azure Function which has authentication enabled and set to require an identity provider:
App Service authentication: Enabled
Restrict access: Require authentication
Unauthenticated requests: Return HTTP 401 Unauthorized
Token store: Enabled
Identity provider - App (client) ID
(Name of App Removed): Client ID Removed
Client Secret Setting Name: Microsoft_Provider_Authentication_Secret
When I use Power Automate to POST to the HTTP function it works. This tells me the security is set up and working as expected. When I try and POST to the function directly from PowerShell using my desktop, I get a 401 unauthorized. This is a GCCH environment.
This is the PowerShell code where I get an oath token and am trying to use that to POST to the HTTP function. I tried using the HTTP URL with and without the 'code=' and neither worked.
#These URLs are used to access get the token; scope has not been required is uses the app ID
$loginURL = "https://login.microsoftonline.us"
$resource = "https://graph.microsoft.us"
$Tenant = "mytenant.onmicrosoft.us"
$ClientID = "removed"
$Secret="removed"
$fcnKey = "removed"
$fcnURL = "https://removed?" #Azure function url without the code at the end
$AuthBody = #{
grant_type="client_credentials";
resource=$resource;
client_id=$ClientID;
client_secret=$Secret}
$Oauth = Invoke-RestMethod -Method POST -Uri $loginURL/$Tenant/oauth2/token?api-version=1.0 -Body
$AuthBody -ContentType "application/x-www-form-urlencoded"
$AuthToken = #{
'Authorization'="$($Oauth.token_type) $($Oauth.access_token)";
'Content-Type' = "application/json";
'x-functions-key' = $fcnkey;}
#This returns a 401 unauthorized
Invoke-RestMethod -Headers $AuthToken -Uri $fcnURL -Method POST
#This also returns a 401 unauthorized
$AuthToken = #{
'Authorization'="$($Oauth.token_type) $($Oauth.access_token)";
'Content-Type' = "application/json";}
$FullURL = "https://removed?code=removed"
Invoke-RestMethod -Headers $AuthToken -Uri $fullURL -Method POST

As #jdweng suggested to check the type of authentication and the process of authorization in this MS Doc of Azure AD Authentication Flows.
Check if the below steps help to fix the issue:
Make Sure you entered the "App ID URI" in the "Allowed Token Audiences" Box.
Same App ID URI should be used for acquiring the token.
Refer to the Similar issue-solutions where 401 Unauthorized error is registered on enabling the App service Authentication on Azure Function App such as MSQ&A337577, SO Questions 67957353 and 55226143.

Related

Azure Devops Run Result Steps and Run Summary Details Attachments API

I am trying to fetch the attachments of the Test Run Result steps and Test Run Result Summary Details but unable to find any API related to that
I am attaching the Image below Rectangle 1 is the attchments for Test Run Result Steps and Rectangele 2 is the attachments for Test Run Result Summary Detais
If anyone have any knowledge about these perticular apis please let me know.
I have checked the AZURE API Documentation but couldn't find the specific API if I have missied something please let me know.
Thanks
By calling the Get Test Result Attachments REST API, we can get all the IDs of the attachments:
GET https://dev.azure.com/{organization}/{project}/_apis/test/Runs/{runId}/Results/{testCaseResultId}/attachments?api-version=6.0-preview.1
After that, if you want to get the attachments you can call Attachments - Get Test Result Attachment Zip REST API with the specific Attachment ID.
GET https://dev.azure.com/{organization}/{project}/_apis/test/Runs/{runId}/Results/{testCaseResultId}/attachments/{attachmentId}?api-version=6.0-preview.1
Please note that the REST API Attachments - Get Test Result Attachment Zip will display the context of the attachments instead of download the attachments directly. If you want to download the attachments, you can write a script to save them to a local directory. The following PowerShell script for your reference:
$AttachmentsOutfile = "D:\Test\HellWorld.java"
$connectionToken="You PAT Here"
$base64AuthInfo= [System.Convert]::ToBase64String([System.Text.Encoding]::
ASCII.GetBytes(":$($connectionToken)"))
$AuditLogURL = "https://dev.azure.com/{organization}/{project}/_apis/test/Runs/{runId}/Results/{testCaseResultId}/attachments/{attachmentId}?api-version=6.0-preview.1"
$AuditInfo = Invoke-RestMethod -Uri $AuditLogURL -Headers #{authorization = "Basic $base64AuthInfo"} -Method Get –OutFile $AttachmentsOutfile
UPDATE:
However the Get Test Result Attachments REST API can only get the attachments attached from the test run UI (attached by clicking the Add attachment button).
To get the attachments of the Test Run Result steps and Test Run Result Summary, we can call Results - Get REST API with parameter detailsToInclude=iterations added:
GET https://dev.azure.com/{organization}/{project}/_apis/test/Runs/{runId}/results/{testCaseResultId}?detailsToInclude=iterations&api-version=6.0
After that we can download the attachments by their ID. The following PowerShell script for your reference to download them in a loop:
Param(
[string]$orgurl = "https://dev.azure.com/{org}",
[string]$project = "Test0924",
[string]$downloadlocation = "C:\temp\1025\",
[string]$TestRunId = "1000294",
[string]$ResultId = "100000",
[string]$user = "",
[string]$token = "PAT"
)
# Base64-encodes the Personal Access Token (PAT) appropriately
$base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $user,$token)))
#List test result and test step attachments:
$testresultUrl = "$orgurl/$project/_apis/test/Runs/$TestRunId/Results/$($ResultId)?detailsToInclude=iterations&api-version=6.0"
$attachments = (Invoke-RestMethod -Uri $testresultUrl -Method Get -Headers #{Authorization=("Basic {0}" -f $base64AuthInfo)}).iterationDetails.attachments
ForEach ($attachment in $attachments) {
#Get test result and step attachments:
$attachmentid = $attachment.id
$attachmentname = $attachment.name
$attachmenturl = "$orgurl/$project/_apis/test/Runs/$TestRunId/Results/$ResultId/attachments/$($attachmentid)?api-version=6.0"
Invoke-RestMethod -Uri $attachmenturl -Method Get -Headers #{Authorization=("Basic {0}" -f $base64AuthInfo)} -OutFile $downloadlocation\$attachmentname
}

Onelogin Powershell API Token

I cannot seem to generate a basic successful call to the onelogin API. I can generate a token from a client ID and secret successfully but every call I do with the token that is output gets a 401. Sample code with replaced token below.
Invoke-RestMethod -Uri https://api.us.onelogin.com/api/2/users? -ContentType application/json -Headers #{Authorization="bearer:12345"} -Method Get
I built the command out by hand to prove it was not some error saving the access_token line out to a variable and still 401.
It was a space needing to be added in the bearer statement.
$Splat = #{
Method = 'GET'
Uri = 'https://api.us.onelogin.com/api/2/users?created_until=2020-07-01T20:38:24Z&last_login_until=2020-07-01T20:38:24Z'
ContentType = "application/json"
Headers = #{authorization = "bearer: $($Token)"}
}
Invoke-RestMethod #Splat

Azure Cognitive Services Read Request with Powershell

I'm trying to use the Azure Cognitive Services API with Powershell to 'read' the contents of a .jpg in a blob store. Everything I am trying to do works perfectly using the Azure API demo/test page, so I am fairly sure that this, to a degree, proves that some elements I'm using in my code are valid. Well, at least they are when using the API testing tool.
Here is my Powershell:
Clear-Host
$myUri = "<ENDPOINT value from "keys and endpoint blade">/vision/v3.0/read/analyze?language=en"
$imagePath = "<path to image in blob. accessible online and anonymously>"
$subKey = "<KEY #1 from "keys and endpoint" blade>"
$headersHash = #{}
$headersHash.Add( "Host", "westeurope.api.cognitive.microsoft.com" )
$headersHash.Add( "Ocp-Apim-Subscription-Key", $subKey )
$headersHash.Add( "Content-Type","application/json" )
$bodyHash = #{ "url" = $imagePath }
out-host -InputObject "Sending request:"
$response = Invoke-WebRequest -uri $myUri `
-Method Post `
-Headers $headersHash `
-Body $bodyHash `
-verbose
"Response: $response"
When I send that, all I ever get is a:
Invoke-WebRequest : The remote server returned an error: (400) Bad Request.
At C:\scratch\testy.ps1:15 char:13
+ $response = Invoke-WebRequest -uri $myUri `
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-W
ebRequest], WebException
+ FullyQualifiedErrorId :
WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeWebRequestCommand
I must be missing something basic but I cannot see what. There are no published examples of using Powershell to access the CS APIs that I can find but there is an example with Python (requests) and I'm pretty sure I'm emulating and representing what goes into the Python example correctly. But then again, its not working so something isn't right.
Strangely, when I try to recreate this in Postman, I get a 202 but no response body, so its not possible for me to view or extract the apim-request-id in order to manufacture the next request to retrieve the results.
Found the issue. The problem was made clear when I wrapped the call in a try/catch block and put this in the catch block:
$streamReader =
[System.IO.StreamReader]::new($_.Exception.Response.GetResponseStream())
$ErrResp = $streamReader.ReadToEnd() | ConvertFrom-Json
$streamReader.Close()
I was then able to look at the contents of the $ErrResp variable and there was a fragment of a string which said "unable to download target image.." or something to that effect. Odd because I could use the URL I was supplying to instantly connect to and get the image.. so it had to be the way the URL was being injecting into the body.
It was.
When using a hashtable as the body, where your Content-Type is 'application/json' all you need to do, it seems, is use convertto-json with your hash first. This worked and I instantly got my 202 and the pointer to where to collect my results.
Hopefully this will help someone, somewhere, sometime.

How to use Azure App Configuration REST API

Trying to figure out how to use Azure AppConfiguration REST API (mostly to retrieve and create key-values). So far I found two sources of information: Configuration Stores REST API docs and this GitHub repo Azure App Configuration.
How these two sources are corresponding with each other? They apparently describe some different AppConfig REST API.
I managed to retrieve values from my AppConfig store using this type of URI and AAD authorization
https://management.azure.com/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.AppConfiguration/configurationStores/{configStoreName}/listKeyValue?api-version=2019-10-01 But it allows to get only one value of one particular key.
The other approach uses URI based on AppConfig endpoint {StoreName}.azconfig.io/kv/... and must have more flexible ways to retrieve data. But I can't make it work. I tried to follow instructions. And I tried to make a request to this URI using AAD token as I did for the first type of API. In both cases I get 401 auth error.
Could anyone share some detailed working examples (Powershell, Postman)? Any help would be appreciated.
https://management.azure.com/ is the Azure Resource Management API, while the azconfig.io one is App Configuration's own API.
I think you should use App Configuration's own API. The same Azure AD token will not work for this API however. You need to request another access token with resource=https://yourstorename.azconfig.io or scope=https://yourstorename.azconfig.io/.default, depending if you use v1 or v2 token endpoint of Azure AD.
Use the $headers in the script to authenticate your api calls:
function Sign-Request(
[string] $hostname,
[string] $method, # GET, PUT, POST, DELETE
[string] $url, # path+query
[string] $body, # request body
[string] $credential, # access key id
[string] $secret # access key value (base64 encoded)
)
{
$verb = $method.ToUpperInvariant()
$utcNow = (Get-Date).ToUniversalTime().ToString("R", [Globalization.DateTimeFormatInfo]::InvariantInfo)
$contentHash = Compute-SHA256Hash $body
$signedHeaders = "x-ms-date;host;x-ms-content-sha256"; # Semicolon separated header names
$stringToSign = $verb + "`n" +
$url + "`n" +
$utcNow + ";" + $hostname + ";" + $contentHash # Semicolon separated signedHeaders values
$signature = Compute-HMACSHA256Hash $secret $stringToSign
# Return request headers
return #{
"x-ms-date" = $utcNow;
"x-ms-content-sha256" = $contentHash;
"Authorization" = "HMAC-SHA256 Credential=" + $credential + "&SignedHeaders=" + $signedHeaders + "&Signature=" + $signature
}
}
function Compute-SHA256Hash(
[string] $content
)
{
$sha256 = [System.Security.Cryptography.SHA256]::Create()
try {
return [Convert]::ToBase64String($sha256.ComputeHash([Text.Encoding]::ASCII.GetBytes($content)))
}
finally {
$sha256.Dispose()
}
}
function Compute-HMACSHA256Hash(
[string] $secret, # base64 encoded
[string] $content
)
{
$hmac = [System.Security.Cryptography.HMACSHA256]::new([Convert]::FromBase64String($secret))
try {
return [Convert]::ToBase64String($hmac.ComputeHash([Text.Encoding]::ASCII.GetBytes($content)))
}
finally {
$hmac.Dispose()
}
}
# Stop if any error occurs
$ErrorActionPreference = "Stop"
$uri = [System.Uri]::new("https://{myconfig}.azconfig.io/kv?api-version=1.0")
$method = "GET"
$body = $null
$credential = "<Credential>"
$secret = "<Secret>"
$headers = Sign-Request $uri.Authority $method $uri.PathAndQuery $body $credential $secret
Sauce: https://github.com/Azure/AppConfiguration/blob/master/docs/REST/authentication/hmac.md#JavaScript

Accessing Function App via App Service Authentication from Dynamics 365 Plugin

I am trying to access an Azure Function from Dynamics 365 Plugin via service to service call: https://learn.microsoft.com/en-us/azure/active-directory/develop/active-directory-protocols-oauth-service-to-service
This function is protected via App Service Authentication.
I created a Function App and enabled App Service Authentication
under Platform Features -> Authentication/Authorisation.
I enabled Azure Active Directory as the Auth Provider and set Management mode to Express
I then got the generated Client ID and Client Secret from the Advanced Mode:
Apparently this is all that is needed to make a token request for the Azure function based, based on article I need 4 required parameters:
Client ID
Client Secret
Grant Type
Resource
I make the following request to generate a token from a Dynamics 365 Plugin but get the following error:
Invalid Plugin Execution Exception: Microsoft.Xrm.Sdk.InvalidPluginExecutionException: {"error":"invalid_client","error_description":"AADSTS70002: Error validating credentials. AADSTS50012: Invalid client secret is provided.\r\nTrace ID: 06ddda7f-2996-4c9b-ab7e-b685ee933700\r\nCorrelation ID: d582e2f2-91eb-4595-b44b-e95f42f2f071\r\nTimestamp: 2018-05-23 06:30:58Z","error_codes":[70002,50012],"timestamp":"2018-05-23 06:30:58Z","trace_id":"06ddda7f-2996-4c9b-ab7e-b685ee933700","correlation_id":"d582e2f2-91eb-4595-b44b-e95f42f2f071"}-The remote server returned an error: (401) Unauthorized.
My code is :
var tokenendpoint = "https://login.microsoftonline.com/de194c13-5ff7-4085-91c3-ac06fb869f28/oauth2/token";
var reqstring = "client_id=" + Uri.EscapeDataString("5f315431-e4da-4f68-be77-4e257b1b9295");
reqstring += "&client_secret=" + Uri.EscapeDataString("/oK7nh8pl+LImBxjm+L7WsQdyILErysOdjpzvA9g9JA=");
reqstring += "&resource=" + Uri.EscapeUriString("https://keyvaultaccess.azurewebsites.net");
reqstring += "&grant_type=client_credentials";
//Token request
WebRequest req = WebRequest.Create(tokenendpoint);
req.ContentType = "application/x-www-form-urlencoded";
req.Method = "POST";
byte[] bytes = System.Text.Encoding.ASCII.GetBytes(reqstring);
req.ContentLength = bytes.Length;
System.IO.Stream os = req.GetRequestStream();
os.Write(bytes, 0, bytes.Length);
os.Close();
//Token response
HttpWebResponse resp = (HttpWebResponse)req.GetResponse();
StreamReader tokenreader = new StreamReader(resp.GetResponseStream());
string responseBody = tokenreader.ReadToEnd();
I have made sure that I have the correct Client Secret and have also encoded it as I have read somewhere that '+' and '/' are no good.
I am getting the same error in Postman
Any ideas??
reqstring += "&resource=" + Uri.EscapeUriString("https://keyvaultaccess.azurewebsites.net");
Since you set resource parameter to https://keyvaultaccess.azurewebsites.net, I assumed that you have set the App ID URI of your AAD app (clientId equals 5f315431-xxxxxxx-4e257b1b9295) to https://keyvaultaccess.azurewebsites.net. I assume that you could retrieve the access_token, but when accessing your azure function endpoint with the access_token, you got the 401 status code.
You need to modify your advanced management mode for Active Directory Authentication, add https://keyvaultaccess.azurewebsites.net to ALLOWED TOKEN AUDIENCES or change the resource parameter to your AAD clientID when sending the token request for acquiring the access_token.
Active Directory Authentication configuration:
TEST:
Docode the JWT token to check the aud property:
Access my Azure Function endpoint:
Note: You need to take care of the Authorization level of your function as follows:
If you also enable function level authentication, your request sent to azure function needs to have the relevant code parameter in the querystring or set the header x-functions-key with the value of your function key, or you may just set the authorization level to Anonymous.

Resources