azureazure-devopsazure-pipelinesazure-devops-rest-apiazure-pipelines-build-task

Azure DevOps REST API: Permissions Not Updating Despite Successful Response


Question:

I am trying to update permissions for a pipeline in Azure DevOps using the REST API, but although I get a 204 No Content response, the permissions are not actually being applied or updated.

What I'm Doing: I'm using the Azure DevOps REST API to update the Access Control Entries (ACL) for a specific pipeline. Below is the POST request payload I am using:

`permissions_payload = {
  "value": [
    {
      "inheritPermissions": False,
      "token": "vstfs:///Classification/TeamProject/{project_id}/{pipeline_id}",
      "acesDictionary": {
        "Microsoft.TeamFoundation.Identity;S-1-9-1551374245-1204400969-2402986413-2179408616-0-0-0-0-1": {
          "descriptor": "Microsoft.TeamFoundation.Identity;S-1-9-1551374245-1204400969-2402986413-2179408616-0-0-0-0-1",
          "principalName": "[{project_name}]\\Contributors",
          "allow": 0,
          "deny": 1
        }
      }
    }
  ]
}

# POST request
response = requests.post(
    permission_url,
    headers=headers,
    json=permissions_payload,
    verify=False
)

if response.status_code == 200 or response.status_code == 204:
    print("Permissions updated successfully.")
else:
    print(f"Failed to update permissions: {response.status_code}")`

Response: I receive a 204 No Content, indicating the request was successful. However, when I check the pipeline's security settings via the Azure DevOps UI, the permissions are not updated.

Steps I've Tried: Checked the descriptor: I'm using the correct descriptor for the "Contributors" group retrieved from the Graph API. Verified the token: The token I'm using follows the format: vstfs:///Classification/TeamProject/{project_id}/{pipeline_id} Tried both inheritPermissions: True and inheritPermissions: False, but the outcome is the same.

My Goal: I want to deny certain permissions for the "Contributors" group on a specific pipeline, but nothing seems to work despite receiving a successful response from the API.


Solution

  • Based on your description, you need to use Rest API to update the Pipeline permissions.

    To meet your requirement, you can use the Rest API: Access Control Entries - Set Access Control Entries

    Update Pipeline permission SecurityNamespaceId : 33344d9c-fc72-4d6f-aba5-fa317101a7e9

    POST https://dev.azure.com/{organization}/_apis/accesscontrolentries/33344d9c-fc72-4d6f-aba5-fa317101a7e9?api-version=6.0
    

    Request Body:

    {
        "token":"{ProjectID}/{PipelineID}",
        "merge":true,
        "accessControlEntries":[{
            "descriptor":"Microsoft.TeamFoundation.Identity;S-1-9-1551374245-491114055-2098815309-2189422963-3385397751-1-479303010-554652490-2991085287-3350433821",
            "allow":16384,
            "deny":16
        }]
    }
    

    To get the descriptor ID, you can use the Rest API: Identities - Read Identities

    GET https://vssps.dev.azure.com/fabrikam/_apis/identities?searchFilter=General&filterValue=[{project_name}]\Contributors&queryMembership=None&api-version=7.0
    

    Python Script sample:

    import requests
    import json
    
    url = "https://dev.azure.com/{orgname}/_apis/accesscontrolentries/33344d9c-fc72-4d6f-aba5-fa317101a7e9?api-version=6.0"
    
    payload = json.dumps({
      "token": "{ProjectID}/{PipelineID}",
      "merge": True,
      "accessControlEntries": [
        {
          "descriptor": "Microsoft.TeamFoundation.Identity;S-1-9-1551374245-491114055-2098815309-2189422963-3385397751-1-479303010-554652490-2991085287-3350433821",
          "allow": 16384,
          "deny": 16
        }
      ]
    })
    headers = {
      'Content-Type': 'application/json',
      'Authorization': 'Basic {Base64PAT}'
    
    }
    
    response = requests.request("POST", url, headers=headers, data=payload)
    
    if response.status_code == 200 or response.status_code == 204:
        print("Permissions updated successfully.")
    else:
        print(f"Failed to update permissions: {response.status_code}")
    
    print(response.text)
    

    Permission value list:

    Administer build permissions: 16384
    
    Delete build pipeline: 4096
    
    Delete builds: 8
    
    Destroy builds: 32
    
    Edit build pipeline: 2048
    
    Edit build quality: 2
    
    Edit queue build configuration: 65536
    
    Manage build qualities: 16
    
    Manage build queue: 256
    
    Override check-in validation by build: 8192
    
    Queue builds: 128
    
    Retain indefinitely: 4
    
    Stop builds: 512
    
    Update build information: 64
    
    View build pipeline: 1024
    
    View builds: 1
    

    If you need to deny multiple permissions, you can plus related numbers.

    For example: deny View builds and View build pipeline permission: 1 + 1024 = 1025

    {
    .....
    "accessControlEntries":[{
        "descriptor":"Microsoft.TeamFoundation.Identity;S-1-9-1551374245-491114055-2098815309-2189422963-3385397751-1-479303010-554652490-2991085287-3350433821",
        "allow":0,
        "deny":1025
    }]
    }
    

    Result:

    enter image description here

    Update:

    If you need to keep using the Rest API and Request body shared in Question: Access Control Lists - Set Access Control Lists, you need to change the token value:

    From:

    "token": "vstfs:///Classification/TeamProject/{project_id}/{pipeline_id}",
    

    To:

    "token": "{project_id}/{pipeline_id}",
    

    In this case, it will work as expected too.