Jess
Jess

Reputation: 69

How to add/update user permissions on environment's security through REST API on Azure DevOps?

screenshot

I need to add user permission when creating an environment through REST API with PowerShell.

I've looked at the network trace and this is the header when I tried to manually add a user permissions

Request URL:

https://dev.azure.com/{org}/_apis/securityroles/scopes/distributedtask.environmentreferencerole/roleassignments/resources/{project_id}_{env_id}

Request Method: Put

Request Body:

[{userId: "{id_of_user}", roleName: "Administrator"}]

And this is the code I tried:

# other code
...
$body = @(
  @{ 'userId' = '{id_of_user}'; 'roleName': 'Administrator' }
) | ConvertTo-Json
Invoke-RestMethod -Uri $uri -Method Put -Body $body -ContentType "application/json" -Headers $header

But it is returning:

{"count":0,"value":{}}

Upvotes: 3

Views: 2008

Answers (3)

Andrei Sinitson
Andrei Sinitson

Reputation: 760

If someone is looking for the cURL + Bash version, here it is:

#!/usr/bin/env bash
set -o errexit # Exit when a command fails
set -o nounset # Exit on undeclared variable
set -o pipefail # Exit on the first command in pipe fail

PERSONAL_ACCESS_TOKEN='<secret>'
GROUP_OR_USER_ID='11111111-1111-1111-1111-111111111111'
ENVIRONMENT_ID='22'
ORGANIZATION=example
PROJECT_ID='33333333-3333-3333-3333-333333333333'
DATA="[{\"userId\":\"${GROUP_OR_USER_ID}\",\"roleName\":\"User\"}]"

URL="https://dev.azure.com/${ORGANIZATION}/_apis/`
    `securityroles/scopes/distributedtask.environmentreferencerole/roleassignments/resources/`
    `${PROJECT_ID}_${ENVIRONMENT_ID}`
    `?api-version=5.0-preview.1"

curl "${URL}" \
    --user ":${PERSONAL_ACCESS_TOKEN}" \
    --request PUT \
    --header 'Content-Type: application/json' \
    --data "${DATA}" \
    | jq # jq is just for pretty JSON printout, not strictly required

NOTE: This can be integrated with Terraform like this.

Upvotes: 0

Justin
Justin

Reputation: 1503

@Bruno answer can have its header greatly simplified, also the body can be constructed using ConvertTo-Json to avoid syntax errors.

function Get-AzureDevOpsAuthenticationHeader
{
    param (
        [Parameter(Mandatory=$false)][SecureString]$PAT
    )
    $AzureDevOpsPAT = (new-object System.Net.NetworkCredential -argumentList " ", (Get-AzureDevOpsPAT -PAT $PAT)).Password
    $AzureDevOpsAuthenicationHeader = @{Authorization = 'Basic ' + [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(":$($AzureDevOpsPAT)")) }
    return $AzureDevOpsAuthenicationHeader
}


#parms
$orgname='...'
$userid='guid'
$projectid='guid'
$environmentid='int'
$PAT = '...' | ConvertTo-SecureString -asplaintext -force

#get the header
$header = Get-AzureDevOpsAuthenticationHeader -PAT $PAT                                                                                                                                                  

#construct the body
$body = ConvertTo-Json -InputObject @(,@{userId= $userid;"roleName"="Administrator"}) 

#send the request
$uri = "https://dev.azure.com/$orgname/_apis/securityroles/scopes/distributedtask.environmentreferencerole/roleassignments/resources/$projectid`_$EnvironmentID`?api-version=5.0-preview.1"

Invoke-RestMethod -UseBasicParsing -Uri $uri -Method "PUT" -Body $body  -ContentType application/json -Headers $header

output:

count value                                                             
----- -----                                                             
    1 {@{identity=; role=; access=assigned; accessDisplayName=Assigned}}

Upvotes: 1

Bruno Assis
Bruno Assis

Reputation: 1006

The only missing thing is that in your body, you should provide an array instead of a single object, here is a working example:

$uri = "https://dev.azure.com/bauca/_apis/securityroles/scopes/distributedtask.environmentreferencerole/roleassignments/resources/{project_id}_{env_id}"
$id_of_user = 'YOUR_USER_ID'
$tokenbase = 'YOUR_PAT'
$header = @{
 "authority"="dev.azure.com"
 "Authorization"= "Basic $tokenbase"
 "method"="PUT"
 "path"="/{ORG}/_apis/securityroles/scopes/distributedtask.environmentreferencerole/roleassignments/resources/{project_id}_{env_id}"
 "scheme"="https"
 "accept"="application/json;api-version=5.0-preview.1;excludeUrls=true;enumsAsNumbers=true;msDateFormat=true;noArrayWrap=true"
 "accept-encoding"="gzip, deflate, br"
 "accept-language"="en-US,en;q=0.9,pt;q=0.8,nl;q=0.7"
 "origin"="https://dev.azure.com"
 "x-vss-reauthenticationaction"="Suppress"
} ` 

$body = "[{`"userId`":`"${id_of_user}`",`"roleName`":`"Administrator`"}]"


Invoke-RestMethod -UseBasicParsing -Uri $uri -Method "PUT" -Body $body -ContentType "application/json" -Headers $header

The returned results should be something like:

@{displayName=USER_NAME; id=USERID; uniqueName=USER_UNIQUENAME} 

The API documentation is not clear about that, so, in this situations what I'd recommend you to do, is just use Chrome to do the requests through the UI, then inspect element and grab the network information of the request, after that 'Click with the right button' and then select 'Copy to Powershell' you'll see exactly what is the 'body' required to perform the request.

Upvotes: 3

Related Questions