Lazy Man's guide to managing Azure Active Directory

For those without patience to click or read through Microsoft's documentation hell

Introduction

There may come a time when the developer or admin must deal with Azure AD and all its quirks. I for instance don't get very excited at the prospect of having to go through Microsoft's documentation or interact with Azure AD questionable interface, whose user experience is less then optimal, for want of a better word.

This guide is for my future self and others too lazy or lacking the necessary inner calmness to actually use Azure AD the way it is intended.

Scope

This tutorial will guide you through extracting the necessary requests from the Azure AD UI and manipulating data so you can automate tasks. To illustrate this, we will migrate users from an OLD APP to a NEW APP, both of which are Enterprise Applications (although this would also work for App Registrations accessed through the Enterprise Applications tabs -- kudos for this excellent UX choice...).

Pre-Requisites

Exploring the problem

Let's say you have two applications in you active directory:

If you need to migrate users between them and you have an Azure AD subscription that enables groups in Enterprise Applications (which requires Active Directory Premium P1 or P2), then you may be in luck: you just have to add the necessary groups into the NEW APP (which hopefully aren't many). If not and you have a sizeable list of users to migrate, you may find yourself having to click through a large list of users, which is both error prone and time consuming.

You could also refer to the Azure AD API documentation. But where to start? You will have to understand exactly how everything translates to the API. Are you dealing with users registered to an application? Is it a service principal? Is the user assignment managed by the application? The user itself? Something else, like a role assignment? I can't really help you here, because I gave up trying to make sense of the API documentation (hence my self denominating a Lazy Man).

It turns out we can just extract the API calls made from Azure AD by interacting with the user interface and manipulate them using a programming language of choice! This lets us delegate to the UI, which is already structured around Microsoft's domain modelling, the task of correlating the many moving parts necessary to achieve our desired user migration.

The plan, therefore, is simple:

  1. get a list of all the users from OLD APP;

  2. add a single user to NEW APP and see which API calls Azure ID does;

  3. modify these calls using the list of users extracted from OLD APP.

Getting the list of users to migrate

Let's go to OLD APP and see what we can find using the dev tools.

After going to OLD APP, open the dev tools (usually by hitting F12) before clicking Users and groups:

(Azure AD didn't let me name Finn the Human for some reason... )

We can see that a GET request is made to AppRoleAssignments. This is exactly what we need. Let's just copy the items attribute from the response and save it to a variable in ipython:

Getting the API Call to add a single user

Now let's head to NEW APP, add a single user and see what we can extract.

In the Users and groups tab, click Add user/group and add a single user you would eventually migrate to the new application:

Before actually clicking Assign, open up the Dev Tools again:

We can see that a POST request is made do appRoleAssignedTo. Let's copy it as cURL and transform to python code using Insomnia:

In Insomnia you just have to paste the cURL string and it will automatically parse it and fill out the necessary fields:

Now we can generate the python code:

Manipulating the API Calls

Now we can use the information extracted when creating the users migration list and modify the API Calls to add other users to NEW APP.

In order to do this, we can study the POST API Call to appRoleAssignedTo to see that we need the principalId, which is fortunately included when listing users from the Application UI.

All we have to do is loop through the list of users and change the principalId from the request payload:

After doing it, we can execute it and see what we end up with:

We can see that we fail to add a user. That is because we previously added a single user in order to extract the API Call and the user can't be added again to this application. Instead, the API returns an error code, which we can just ignore.

The other logs tell us that we successfully added the other two users to NEW APP. Let's double check in the Azure AD portal:

Well that was easy! Easier then having to become a Microsoft Documentation expert.

Conclusion

Using this approach we can automate many other one-shot administrative operations without having to understand how they translate to the actual Azure AD API. For instance, this also applies, albeit with some tweaks to the API Call manipulation, to migrating users from different Azure AD groups, so even if you have a subscription that allows you to easily manage access to multiple Enterprise Application, this approach might come in handy.

Considerations to using this approach:

  1. The Bearer token isn't valid for long. If you have to migrate an unusually large number of users, you may have to optimize a few steps, like:

    1. parallelize the POST API Calls

    2. implement continuation logic or ask for a new token, which can be extracted from a new API Call

  2. Azure only displays the first 200 users, so if you have to migrate more users than that, use the same approach for the POST API, and modify the GET call to set an arbitrary number of users, using the top header.

  3. Azure may break the list of users in chunks. If that is the case, I couldn't force the API to retrieve the entire list using the approach described in 2., but clicking More... will make another call with the list continuation. Just do this until you end up with the complete users list and concatenate the items from the API Calls in ipython.

The Digital Meadow logo
Subscribe to The Digital Meadow and never miss a post.
#python#azure#active directory#dev tools#ipython#requests#tutorial
  • Loading comments...