Rest API call using Powershell - CosmosDb

I tried to deploy a space database using Cosmos DB REST Api. I use the function to create an authorization header, and I got the script link from https://gallery.technet.microsoft.com/scriptcenter/How-to-query-Azure-Cosmos-0a9aa517 . It works great for GET and POST, but when I tried to execute the PUT command, I always get below the error.

Invoke-RestMethod: The remote server returned an error: (401) Unauthorized.

I am trying to update the Cosmos collection offer, but it always fails, and I could not understand what was the reason. I also checked my headers and authorization with Microsoft documentation and looked great at me. See https://docs.microsoft.com/en-us/rest/api/documentdb/replace-an-offer for Uri and required headers. My request and answer below

Request

PUT https: //mycosmosdb.documents.azure.com:443/offers/mycollection HTTP/1.1 authorization: type % 3dmaster % 26ver % 3d1.0 % 26sig % 3dIgWkszNS % 2b94fUEyrG8frByB2PWSc1ZEszc06GUeuW7s % 3d x - ms - version: 2017 - 02 - 22 x - ms - date: Wed, 02 Aug 2017 08: 40: 37 GMT User - Agent: Mozilla / 5.0(Windows NT; Windows NT 10.0; en - US)WindowsPowerShell / 5.1.15063.483 Content - Type: application / json Host: mycosmosdb.documents.azure.com Content - Length: 269 { "offerVersion": "V2", "offerType": "Invalid", "content": { "offerThroughput": 500, "offerIsRUPerMinuteThroughputEnabled": false }, "resource": "dbs/xterf==/colls/STuexopre=/", "offerResourceId": "STuexopre=", "id": "xiZw", "_rid": "xiZw" } 

answer

 HTTP / 1.1 401 Unauthorized Transfer - Encoding: chunked Content - Type: application / json Content - Location: https: //mycosmosdb.documents.azure.com/offers/variantstockquantity Server: Microsoft - HTTPAPI / 2.0 x - ms - activity - id: 6f7be3c8 - cfa2 - 4d5e - ad69 - fb14ef218980 Strict - Transport - Security: max - age = 31536000 x - ms - gatewayversion: version = 1.14.57.1 Date: Wed, 02 Aug 2017 08: 40: 35 GMT 163{ "code": "Unauthorized", "message": "The input authorization token can't serve the request. Please check that the expected payload is built as per the protocol, and check the key being used. Server used the following payload to sign: 'put\noffers\mycollection\nwed, 02 aug 2017 08:40:37 gmt\n\n'\r\nActivityId: 6f7be3c8-cfa2-4d5e-ad69-fb14ef218980" } 0 

My Powershell Code

 Function Generate-MasterKeyAuthorizationSignature { [CmdletBinding()] Param ( [Parameter(Mandatory=$true)][String]$verb, [Parameter(Mandatory=$true)][String]$resourceLink, [Parameter(Mandatory=$true)][String]$resourceType, [Parameter(Mandatory=$true)][String]$dateTime, [Parameter(Mandatory=$true)][String]$key, [Parameter(Mandatory=$true)][String]$keyType, [Parameter(Mandatory=$true)][String]$tokenVersion ) $hmacSha256 = New-Object System.Security.Cryptography.HMACSHA256 $hmacSha256.Key = [System.Convert]::FromBase64String($key) If ($resourceLink -eq $resourceType) { $resourceLink = "" } $payLoad = "$($verb.ToLowerInvariant())`n$($resourceType.ToLowerInvariant())`n$resourceLink`n$($dateTime.ToLowerInvariant())`n`n" $hashPayLoad = $hmacSha256.ComputeHash([System.Text.Encoding]::UTF8.GetBytes($payLoad)) $signature = [System.Convert]::ToBase64String($hashPayLoad); [System.Web.HttpUtility]::UrlEncode("type=$keyType&ver=$tokenVersion&sig=$signature") } Function Modify-Offer { [CmdletBinding()] Param ( [Parameter(Mandatory=$true)][String]$DocumentDBApi, [Parameter(Mandatory=$true)][String]$EndPoint, [Parameter(Mandatory=$true)][String]$MasterKey, [Parameter(Mandatory=$true)][String]$CollectionName ) $Verb = "PUT" $ResourceType = "offers"; $ResourceLink = "offers" $body = '{ "offerVersion": "V2", "offerType": "Invalid", "content": { "offerThroughput": 500, "offerIsRUPerMinuteThroughputEnabled": false }, "resource": "dbs/xterf==/colls/STuexopre=/", "offerResourceId": "STuexopre=", "id": "xiZw", "_rid": "xiZw" }' $dateTime = [DateTime]::UtcNow.ToString("r") $authHeader = Generate-MasterKeyAuthorizationSignature -verb $Verb -resourceLink $ResourceLink -resourceType $ResourceType -key $MasterKey -keyType "master" -tokenVersion "1.0" -dateTime $dateTime $header = @{authorization=$authHeader;"x-ms-version"=$DocumentDBApi;"x-ms-date"=$dateTime} $contentType= "application/json" $queryUri = "$EndPoint$ResourceLink/$CollectionName" $result = Invoke-RestMethod -Method $Verb -ContentType $contentType -Uri $queryUri -Headers $header -Body $body $result | ConvertTo-Json -Depth 10 } Modify-Offer -EndPoint $CosmosDBEndPoint -MasterKey $MasterKey -DocumentDBApi $DocumentDBApiVersion -CollectionName $ColName 

Can someone tell me why my PUT requests failed with an authorization error, what I am missing and how I can fix it.

+5
source share
1 answer

The response message clearly indicates the payload used for verification. The $ payLoad trace in the Generate-MasterKeyAuthorizationSignature will quickly fix the problem.

To do this, you need to address at least two reasons:

  • The RepalceOffer documentation contains the RID of the offer, instead you are passing the collection name.
  • ResourceLin hardcoded: $ ResourceLink = "offers" in Modify-Offer, where it must point to the RID of the resource.

Here is a slightly modified code that should do the job

 Function Generate-MasterKeyAuthorizationSignature { [CmdletBinding()] Param ( [Parameter(Mandatory=$true)][String]$verb, [Parameter(Mandatory=$true)][String]$resourceLink, [Parameter(Mandatory=$true)][String]$resourceType, [Parameter(Mandatory=$true)][String]$dateTime, [Parameter(Mandatory=$true)][String]$key, [Parameter(Mandatory=$true)][String]$keyType, [Parameter(Mandatory=$true)][String]$tokenVersion ) $hmacSha256 = New-Object System.Security.Cryptography.HMACSHA256 $hmacSha256.Key = [System.Convert]::FromBase64String($key) If ($resourceLink -eq $resourceType) { $resourceLink = "" } $payLoad = "$($verb.ToLowerInvariant())`n$($resourceType.ToLowerInvariant())`n$resourceLink`n$($dateTime.ToLowerInvariant())`n`n" $hashPayLoad = $hmacSha256.ComputeHash([System.Text.Encoding]::UTF8.GetBytes($payLoad)) $signature = [System.Convert]::ToBase64String($hashPayLoad); Write-Host $payLoad [System.Web.HttpUtility]::UrlEncode("type=$keyType&ver=$tokenVersion&sig=$signature") } Function Modify-Offer { [CmdletBinding()] Param ( [Parameter(Mandatory=$true)][String]$DocumentDBApi, [Parameter(Mandatory=$true)][String]$EndPoint, [Parameter(Mandatory=$true)][String]$MasterKey, [Parameter(Mandatory=$true)][String]$OfferRID ) $Verb = "PUT" $ResourceType = "offers"; $body = '{ "offerVersion": "V2", "offerType": "Invalid", "content": { "offerThroughput": 600, "offerIsRUPerMinuteThroughputEnabled": false }, "resource": "dbs/xterf==/colls/STuexopre=/", "offerResourceId": "STuexopre=", "id": "xiZw", "_rid": "xiZw" }' $dateTime = [DateTime]::UtcNow.ToString("r") $authHeader = Generate-MasterKeyAuthorizationSignature -verb $Verb -resourceLink $OfferRID -resourceType $ResourceType -key $MasterKey -keyType "master" -tokenVersion "1.0" -dateTime $dateTime $header = @{authorization=$authHeader;"x-ms-version"=$DocumentDBApi;"x-ms-date"=$dateTime} $contentType= "application/json" $queryUri = "$EndPoint$ResourceType/$OfferRID" $result = Invoke-RestMethod -Method $Verb -ContentType $contentType -Uri $queryUri -Headers $header -Body $body $result | ConvertTo-Json -Depth 10 } Modify-Offer -EndPoint $CosmosDBEndPoint -MasterKey $MasterKey -DocumentDBApi $DocumentDBApiVersion -OfferRID $ColName 

Another alternative recommended approach, if possible, is to use the Powershell client SDK. Here is a sample code that updates the first sentence of an account.

 Add-Type -Path "...\Microsoft.Azure.Documents.Client.dll" $client=New-Object Microsoft.Azure.Documents.Client.DocumentClient($CosmosDBEndPoint, $MasterKey) $offersEnum=$client.ReadOffersFeedAsync().Result.GetEnumerator(); if ($offersEnum.MoveNext()) { $targetOffer=$offersEnum.Current $offerUpdated=New-Object Microsoft.Azure.Documents.OfferV2($targetOffer, 600, $FALSE) $client.ReplaceOfferAsync($offerUpdated).Result } 
+3
source

Source: https://habr.com/ru/post/1270479/


All Articles