Azure AD : Retrieving All Users in Application Roles Programmatically
Background
Essentially there are two ways using which you can achieve this e.g. either using HTTP REST calls (Graph Api) and using Azure AD SDK. This article covers the details of second approach i.e. how we can query and retrieve all users in an application role using Azure AD managed providers.
Since we are interested in getting users from a Azure AD application role, we would need the application role Id against which we will be querying so we will first retrieve all the role Ids from an Azure AD application.
Note that this article assumes that you have basic understanding of Azure AD and application roles, if not then it is highly recommended that you go through this article before moving ahead.
Show Me the Code
Oh yes, here we go
public static Dictionary<string, string> GetAllAppRoles()
{
get
{
if (appRolesDictionary == null || appRolesDictionary.Count == 0)
{
appRolesDictionary = new Dictionary<string, string>();
string tenantID = ClaimsPrincipal.Current.FindFirst("http://schemas.microsoft.com/identity/claims/tenantid").Value;
Uri servicePointUri = new Uri(("https://graph.windows.net");
Uri serviceRoot = new Uri(servicePointUri, tenantID);
ActiveDirectoryClient activeDirectoryClient = new ActiveDirectoryClient(serviceRoot, async () => await UserHelper.GetTokenForApplication());
IPagedCollection<IApplication> retrievedApps = activeDirectoryClient.Applications.Where(w => w.AppId.Equals(ConfigHelper.ClientId)).ExecuteAsync().Result;
if (retrievedApps != null)
{
Application adApp = (Application)retrievedApps.CurrentPage.FirstOrDefault();
if (adApp != null)
{
adApp.AppRoles.ToList().ForEach(e =>
{
appRolesDictionary.Add(e.DisplayName, e.Id.ToString());
});
}
}
}
return appRolesDictionary;
}
}
The snippet above builds a dictionary with key as application role name and value as it’s Id. The ConfigHelper.Client is nothing but the Azure AD application Id which is registered and to which application roles are associated.
Now the next part, we will now be creating a method which accepts two arguments i.e. application role id and service principle Id. For those who do not know what service principle Id is, without going to technicalities we can just say in simple terms that it is the object Id present along with your Application Id in Azure AD app registration details and can be retrieved easily using Azure portal
[Image here]
Now let’s look at our core method
public static List<IUser> GetAllUsersInAppRole(string servicePrincipalObjectId, string appRoleId)
{
string tenantID = ClaimsPrincipal.Current.FindFirst("http://schemas.microsoft.com/identity/claims/tenantid").Value;
Uri servicePointUri = new Uri("https://graph.windows.net");
Uri serviceRoot = new Uri(servicePointUri, tenantID);
ActiveDirectoryClient activeDirectoryClient = new ActiveDirectoryClient(serviceRoot, async () => await GetTokenForApplication());
List<IUser> users = new List<IUser>();
var guidAppRoleId = Guid.Parse(appRoleId);
var appRoleAssignmentsPaged = activeDirectoryClient.ServicePrincipals.GetByObjectId(servicePrincipalObjectId).AppRoleAssignedTo.ExecuteAsync().Result;
var appRoleAssignments = EnumerateAllAsync(appRoleAssignmentsPaged);
var userObjectIds = appRoleAssignments.Where(a => a.Id == guidAppRoleId && a.PrincipalType == "User").Select(a => a.PrincipalId.ToString()).ToList();
foreach (var userObjectId in userObjectIds)
{
users.Add(activeDirectoryClient.Users.Where(w => w.ObjectId.Equals(userObjectId)).ExecuteAsync().Result.CurrentPage.FirstOrDefault());
}
return users;
}
There is an additional extension method we have written to enumerate all the paged collections
public static IEnumerable<T> EnumerateAllAsync<T>(this IPagedCollection<T> pagedCollection)
{
return EnumerateAllAsync(pagedCollection, Enumerable.Empty<T>());
}
private static IEnumerable<T> EnumerateAllAsync<T>(this IPagedCollection<T> pagedCollection, IEnumerable<T> previousItems)
{
var newPreviousItems = previousItems.Concat(pagedCollection.CurrentPage);
if (pagedCollection.MorePagesAvailable == false)
{
return newPreviousItems;
}
var newPagedCollection = pagedCollection.GetNextPageAsync().Result;
return EnumerateAllAsync(newPagedCollection, newPreviousItems);
}
And that’s it, now the method call can be made quite conveniently i.e.
Dictionary<string, string> allAppRoles = GetAllAppRoles();
allAppRoles.TryGetValue(roleName, out string roleId);
List<IUser> appRoleUsers = GetAllUsersInAppRole("app_object_Id",roleId)
That’s all folks, hope this will helps someone.
References
Below are few links which were referenced while creating / writing methods mentioned above
Conclusion
Though there is no direct and straight forward way to query and retrieve all the Azure AD users belonging to Azure AD Application roles, hope it will be in place in upcoming releases of Azure SDK but for now above approach works well.