Mocking Auth Token function in Pester - powershell

I have written a PowerShell function that generates an auth token in azure using REST API call. I am using the tenant id, Service principal client id and client secret as input param to generate this token. The SP client id and client secret are being read from the azure keyvault.
I wish to write a unit test to:
Read secret from keyvault
Mock the REST API call to generate dummy auth token
I am planning to use PESTER for unit testing and need some assistance here.
Here is my function:
function string GetAuthToken() {
$AuthTokenUri = "https://login.microsoftonline.com/$TenantId/oauth2/token"
$Body = #{
'resource' = $resourcename
'client_id' = $ID
'grant_type' = 'client_credentials'
'client_secret' = $Secret
}
$Token = Invoke-RestMethod -Method Post -Uri $AuthTokenUri -Body $Body -ContentType application/x-www-form-urlencoded'
$AuthToken = ($Token.access_token).ToString()
return $AuthToken
}

Related

Microsoft Graph API Bearer Token expires after an hour, can I extend it?

I have a PowerShell script that uploads data to a SharePoint site, however, the script needs more than an hour to upload all the data. Is there anyway to increase the tokens life span. Below is the call I use to get the Bearer token
$TenantId = "T123"
$ClientId = "C123"
$Secret = "S123"
$uri = "https://login.microsoftonline.com/$TenantId/oauth2/v2.0/token "
$body = #{
grant_type = "client_credentials"
client_id = $ClientId
client_secret = $Secret
scope = "https://graph.microsoft.com/.default"
}
#call to get access token
$resp = Invoke-RestMethod -Method Post -Uri $uri -Body $body -ContentType "application/x-www-form-urlencoded"

How do I Invoke a REST API from Azure DevOps using Bearer Token

I'm trying to use an Azure DevOps task to programatically assign a LUIS predict resource to a LUIS app, as documented here. In short, this involves
Get an Azure Resource Manager token from this website.
Assign a LUIS azure accounts to an application, using Bearer token from previous step.
I am able to execute these steps manually, but how to I do this from Azure DevOps?
I have tried to use a 'Invoke REST API' task from an agentless job, but don't see how I can retrieve and use the Bearer token.
Note the Bearer token expires.
Thanks for your advice.
You can add a powershell task in your pipeline to do this from azure devops.
Get an Azure Resource Manager token: You can refer to below powershell scripts to get the token. Check here for more information about where to get client id and client secret. Please be noted that the resource here is "https://management.core.windows.net/"
$client_id = "{client id}"
$client_secret = "{client secret}"
$uri= "https://login.microsoftonline.com/{tenant id}/oauth2/token"
$Body = #{
'resource'= "https://management.core.windows.net/"
'client_id' = $client_id
'grant_type' = 'client_credentials'
'client_secret' = $client_secret
}
$params = #{
ContentType = 'application/x-www-form-urlencoded'
Headers = #{'accept'='application/json'}
Body = $Body
Method = 'Post'
URI = $uri
}
$response = Invoke-RestMethod #params
$token = $response.access_token
After the you got the token you can pass it to the LUIS rest api. Below script is just for example.
$LuisBody = #{
"azureSubscriptionId"= "{subscription_id}"
"resourceGroup"= "{resource_group_name}"
"accountName"= "{account_name}"
}
$Luisparams = #{
Headers = #{
Authorization = ("Bearer {0}" -f $token) # pass the token which got from above script
"Ocp-Apim-Subscription-Key" = "{subscription key}"
ContentType = "application/json"
}
Body = $LuisBody
Method = 'Post'
URI = "https://{endpoint}/luis/api/v2.0/apps/{appId}/azureaccounts"
}
Invoke-RestMethod #Luisparams
There is another blog you might find helpful.
Update:
GetAzure Resource Manager token with Azure CLI with below script:
az account get-access-token --resource=https://management.core.windows.net/ | jq -r .accessToken
Check official documents here, and here for an example.

Microsoft Graph API - app in powershell - forbidden response

I am attempting to make a Microsoft Graph API call using powershell 5.1. I have Registred the app. I use the AppID and secret to obtain an Authorization Bearer token. I then construct my API request. The security/events endpoint only returns a Forbidden response.
API Permissions Granted
My script to make the call looks like this:
# Define AppId, secret and scope, your tenant name and endpoint URL
$AppId = [myAPPID]
$AppSecret = [myAPPSecret]
$Scope = "https://graph.microsoft.com/.default"
$TenantName = "[mytenant].onmicrosoft.com"
$Url = "https://login.microsoftonline.com/$TenantName/oauth2/v2.0/token"
# Add System.Web for urlencode
Add-Type -AssemblyName System.Web
$Body = #{
client_id = $AppId
client_secret = $AppSecret
scope = $Scope
grant_type = 'client_credentials'
}
# Splat the parameters for Invoke-Restmethod for cleaner code
$PostSplat = #{
ContentType = 'application/x-www-form-urlencoded'
Method = 'POST'
# Create string by joining bodylist with '&'
Body = $Body
Uri = $Url
}
$Request = Invoke-RestMethod #PostSplat
$Header = #{
Authorization = "$($Request.token_type) $($Request.access_token)"
}
$Uri = "https://graph.microsoft.com/v1.0/security/events"
$SecurityAlertsRequest = Invoke-RestMethod -Uri $Uri -Headers $Header -Method Get -ContentType "application/json"
Just looking to see If I have missed something obvious. Is there any other reason this would response with Forbidden for this configuration?
You have granted delegated permissions to the app.
Those only apply when there is a user signed in to your app and you acquire an access token to act on their behalf.
You need to grant application permissions to your app in Azure AD.

How to authenticate to Azure REST API using username and password (no App Id)

I need to acquire access token for accessing resources in Azure (https://management.azure.com endpoint) using REST API. Every article a have read, was counting with Appliction Id. In my case, the Azure tenant was just created (programatically) and I have to create some resources in it.
Only thing I have is tenant id, subscription id, user name and password of admin account. How can I authenticate using only information I have? How it works in PowerShell, that does not need to use an Application Id?
Based on my knowledge, it is impossible. As junnas said, even you use user/password authentication, client id is also required.
It is easy for you to create a service principal on Azure, you could check this link.
After the sp is created, you will get the client id, client secret. You also need give the sp Owner role on subscription, you could check this link.
Now, you could use the sp to call rest api in Power Shell, for example.
##get token
$TENANTID=""
$APPID=""
$PASSWORD=""
$result=Invoke-RestMethod -Uri https://login.microsoftonline.com/$TENANTID/oauth2/token?api-version=1.0 -Method Post -Body #{"grant_type" = "client_credentials"; "resource" = "https://management.core.windows.net/"; "client_id" = "$APPID"; "client_secret" = "$PASSWORD" }
$token=$result.access_token
##set subscriptionId and resource group name
$subscriptionId=""
$resourcegroupname="shui5"
$Headers=#{
'authorization'="Bearer $token"
'host'="management.azure.com"
'contentype'='application/json'
}
$body='{
"location": "northeurope",
"tags": {
"tagname1": "test-tag"
}
}'
Invoke-RestMethod -Uri "https://management.azure.com/subscriptions/$subscriptionId/resourcegroups/${resourcegroupname}?api-version=2015-01-01" -Headers $Headers -Method PUT -Body $body
You can use the Microsoft PowerShell Application ID to authenticate without having your own Application ID. This code snipet will give you the token:
Import-Module MSOnline # IMPORTANT! Loads type assembly Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext
$TENANTID = "" # Your Tenant ID
$clientId = "1b730954-1685-4b74-9bfd-dac224a7b894" # PowerShell Client Id
$MSMgmtURI = "https://management.core.windows.net"
$authority = "https://login.microsoftonline.com/$TENANTID"
$redirectUri = "urn:ietf:wg:oauth:2.0:oob"
$authContext = New-Object "Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext" -ArgumentList $authority
$authResult = $authContext.AcquireToken($MSMgmtURI, $clientId, $redirectUri, "Always")
$token = $authResult.AccessToken
$headers = #{'Authorization' = "Bearer $token", 'host'="management.azure.com", 'Content-Type' = "application/json"}
This is good for getting an access token using the login dialog. I suspect that the Client ID for PowerShell could be used in the Oath2 call above.

Azure CDN - Custom Domain SSL via Resource Management API

Using the latest Azure Powershell SDK, but still can't seem to create Custom SSL Domains for CDNs in Azure via API Management. We have 100s of subdomains to create and need to be able to script the creation of this task for future extensibility.
Does anyone know how to toggle this flag via the REST API since the SDK has no support? We are using the New-AzureRmCdnCustomDomain commandlet.
Update: The AzureRM 6.13.0-module and the new Az-modules (including Az.Cdn) now supports this using a cmdlet. See Enable-AzureCdnCustomDomain (AzureRM.Cdn) or Enable-AzCdnCustomDomain (Az.Cdn)
The REST API for enabling Custom Domain HTTPS is documented at learn.microsoft.com
Enable Custom Https
Enable https delivery of the custom domain.
POST /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Cdn/profiles/{profileName}/endpoints/{endpointName}/customDomains/{customDomainName}/enableCustomHttps?api-version=2017-10-12
Before you can use the Azure REST API you need to get an access token:
Generating access token using PowerShell:
$Token = Invoke-RestMethod -Uri https://login.microsoftonline.com/<TenantID>/oauth2/token?api-version=1.0 -Method Post -Body #{
"grant_type" = "client_credentials"
"resource" = "https://management.core.windows.net/"
"client_id" = "<application id>"
"client_secret" = "<password you selected for authentication>"
}
The response contains an access token, information about how long that
token is valid, and information about what resource you can use that
token for. The access token you received in the previous HTTP call
must be passed in for all request to the Resource Manager API. You
pass it as a header value named "Authorization" with the value "Bearer
YOUR_ACCESS_TOKEN". Notice the space between "Bearer" and your access
token.
Client ID is retrived by creating an app registration in Azure AD and the clientkey is generated in the Keys-section of the created app registration. This can be combined into a solution like this:
$subscriptionId = "..."
$resourceGroupName = "..."
$profileName = "..."
$endpointName = "..."
$customDomainName = ".."
$Token = Invoke-RestMethod -Uri https://login.microsoftonline.com/<TenantID>/oauth2/token?api-version=1.0 -Method Post -Body #{
"grant_type" = "client_credentials"
"resource" = "https://management.core.windows.net/"
"client_id" = "<application id>"
"client_secret" = "<password you selected for authentication>"
}
$header = #{
"Authorization"= "Bearer $($Token.access_token)"
}
Invoke-RestMethod -Method Post -Headers $header -Uri "https://management.azure.com/subscriptions/$subscriptionId/resourceGroups/$resourceGroupName/providers/Microsoft.Cdn/profiles/$profileName/endpoints/$endpointName/customDomains/$customDomainName/enableCustomHttps?api-version=2016-10-02"
If you don't need to automate the script, you can login manually using GUI (no need for app-registration) using this modified sample (based on Source). It requires AzureRM-module, which can be installed using Install-Module AzureRM:
Function Login-AzureRESTApi {
Import-Module AzureRM.Profile
# Load ADAL Azure AD Authentication Library Assemblies
$modulepath = Split-Path (Get-Module -Name AzureRM.Profile).Path
$adal = "$modulepath\Microsoft.IdentityModel.Clients.ActiveDirectory.dll"
$adalforms = "$modulepath\Microsoft.IdentityModel.Clients.ActiveDirectory.WindowsForms.dll"
$null = [System.Reflection.Assembly]::LoadFrom($adal)
$null = [System.Reflection.Assembly]::LoadFrom($adalforms)
# Login to Azure
$Env = Login-AzureRmAccount
# Select Subscription
$Subscription = (Get-AzureRmSubscription | Out-GridView -Title "Choose a subscription ..." -PassThru)
$adTenant = $Subscription.TenantId
$global:SubscriptionID = $Subscription.SubscriptionId
# Client ID for Azure PowerShell
$clientId = "1950a258-227b-4e31-a9cf-717495945fc2"
# Set redirect URI for Azure PowerShell
$redirectUri = "urn:ietf:wg:oauth:2.0:oob"
# Set Resource URI to Azure Service Management API | #marckean
$resourceAppIdURIASM = "https://management.core.windows.net/"
$resourceAppIdURIARM = "https://management.azure.com/"
# Set Authority to Azure AD Tenant
$authority = "https://login.windows.net/$adTenant"
# Create Authentication Context tied to Azure AD Tenant
$authContext = New-Object "Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext" -ArgumentList $authority
# Acquire token
$global:authResultASM = $authContext.AcquireToken($resourceAppIdURIASM, $clientId, $redirectUri, "Auto")
$global:authResultARM = $authContext.AcquireToken($resourceAppIdURIARM, $clientId, $redirectUri, "Auto")
}
$resourceGroupName = "..."
$profileName = "..."
$endpointName = "..."
$customDomainName = ".."
Login-AzureRESTApi
#Reuse selected subscription from login
$Subscription = $global:subscriptionId
$header = #{
"Authorization"= $global:authResultARM.CreateAuthorizationHeader()
}
Invoke-RestMethod -Method Post -Headers $header -Uri "https://management.azure.com/subscriptions/$subscriptionId/resourceGroups/$resourceGroupName/providers/Microsoft.Cdn/profiles/$profileName/endpoints/$endpointName/customDomains/$customDomainName/enableCustomHttps?api-version=2017-10-12"