Search code examples
pythonapiazure-devopsclientazure-devops-rest-api

How to add a user to Azure DevOps using it's python client API?


I am writing a python script to add a user(an existing user from the AAD backed provider) to Azure DevOps. I am using python client library of Azure DevOps for this purpose. After authentication, I am able to fetch the users from azure devops as:

# Create a connection to the org
credentials = BasicAuthentication('', personal_access_token)
connection = Connection(base_url=organization_url, creds=credentials)

# Get a client (the "graph" client provides access to list,get and create user)
graph_client = connection.clients_v5_0.get_graph_client()
resp = graph_client.list_users()

# Access the properties of object as object.property
users = resp.graph_users

# Show details about each user in the console
for user in users:
    pprint.pprint(user.__dict__)
    print("\n")

How to add a user using this GraphClient connection?

There is a create_user function ( use as graph_client.create_user() ) here to do this: https://github.com/microsoft/azure-devops-python-api/blob/dev/azure-devops/azure/devops/v5_0/graph/graph_client.py

It says that the request should include a GraphUserCreationContext as an input parameter.

But how can I get that GraphUserCreationContext for an AAD user? I only have information about the AAD user's UPN as input.

Note:

I found .NET sample to do this here : https://github.com/microsoft/azure-devops-dotnet-samples/blob/master/ClientLibrary/Samples/Graph/UsersSample.cs

It uses GraphUserPrincipalNameCreationContext which extends GraphUserCreationContext.

But i couldn't find such a class in python client library. I used the code like this:

addAADUserContext = GraphUserCreationContext('[email protected]')
print(addAADUserContext)
resp = graph_client.create_user(addAADUserContext)
print(resp) 

But got an error:

azure.devops.exceptions.AzureDevOpsServiceError: VS860015: Must have exactly one of originId or principalName set.

Solution

  • GraphUserCreationContext class from the python client for azure devops REST API accepts only one input parameter which is StorageKey. Hence, whatever you provide as an input parameter to that function, be it a UPN or ID, it is set as a storage key.

    If you print the addAADUserContext object, you will get:

    {'additional_properties': {}, 'storage_key': '[email protected]'}
    

    But the create_user() function of Graph client needs exactly one of originId or principalName set in the GraphUserCreationContext it takes as input parameter.

    As the microsoft documentaion for the azure devops REST API (https://learn.microsoft.com/en-us/rest/api/azure/devops/graph/users/create?view=azure-devops-rest-4.1 ) :

    The body of the request must be a derived type of GraphUserCreationContext:

    • GraphUserMailAddressCreationContext
    • GraphUserOriginIdCreationContext
    • GraphUserPrincipalNameCreationContext

    We shouldn't use the GraphUserCreationContext object directly. But the classes like GraphUserPrincipalNameCreationContext aren't currently available in the python client API. They are working on it. You can track the issue here in GitHub repo: https://github.com/microsoft/azure-devops-python-api/issues/176

    You can use User Entitlements - Add REST API for azure devops instead of it's Graph API. You can use the following python client for this purpose:

    https://github.com/microsoft/azure-devops-python-api/tree/dev/azure-devops/azure/devops/v5_0/member_entitlement_management

    You can refer to the sample given in the following question to know about how to use the mentioned python client :

    Unable to deserialize to object: type, KeyError: ' key: int; value: str '