Cristian
Cristian

Reputation: 61

Retrieve Roles and Users per Application in Microsoft Graph

I am developing a Application/Role/User Management web app using Microsoft.Graph. What I need is to retrieve the users and roles related to an application deployed in the Azure Portal. I was able to retrieve Roles and Applications by user using Client.Users[id].AppRoleAssignments but I have around 8000 users and I need to list roles and users per application. I have used Microsoft Graph and Azure.ActiveDirectory.GraphDirectory since I know some of that the Azure library is more comprehensive with no luck. I also tried using client.servicePrincipals but they are not returning users and roles as I expected. Could you give a hand of how could I accomplish this?

Many thanks !!

Upvotes: 6

Views: 14708

Answers (2)

OJB1
OJB1

Reputation: 2785

The examples I've shown below are what I've used to get the list of App Roles for the current service principal (service principal being your app) The screenshot shows the list of App Roles that I created for one of my applications, the App Roles will govern what pages/methods can be called in my app as an access control system.

enter image description here

I got the service principal ObjectId string from the below area in the Azure AD portal. Go to AzureAd --> Home --> YourTenant --> EnterpriseApplications --> then select your current application from the list:

enter image description here

Example 1 - Using MS Graph SDK

public async Task<JsonResult> OnGetGetAppRolesForCurrentServicePrincipalAsync()
{
    // Get the current user properties from the httpcontext currentUser repository for logging.
    CurrentUserProperties currentUser = (CurrentUserProperties)_currentUser.GetCurrentUser();

    // Get an instance of the log extension class.
    LogExtension logExtension = new(_configuration);

    GraphServiceClient graphClient = GetGraphServiceClient(new[]
    {
        GraphScopes.DirectoryReadAll,
        GraphScopes.AppRoleAssignmentReadWriteAll,
        GraphScopes.DirectoryReadWriteAll,
        GraphScopes.DirectoryAccessAsUserAll
        // May not require all these scopes, am doing other things later in this method
    });

    try
    {
        var appRoleAssignmentsForCurrentServicePrincipal = await graphClient.ServicePrincipals["your-service-principal-id-string-here"]
            .Request()
            .GetAsync();

        if (appRoleAssignmentsForCurrentServicePrincipal.AppRoles.Any())
        {
            foreach(var role in appRoleAssignmentsForCurrentServicePrincipal.AppRoles)
            {
                // Do Something here with the list of App Roles
            }
        }
        else
        {
           return new JsonResult(new { success = false, 
           responseText = "No results were found when fecthing the list of app roles for the current service principal" });
        }
    }
    catch (ServiceException ex)
    {
        // Graph service exception friendly message
        var errorMessage = ex.Error.Message;
        LogData = " Error fetching the App Roles. Microsoft Graph returned an error with message [" + errorMessage + "]";
        logExtension.WriteLogEvent<EditModel>("Error", "App Roles", "Get App Roles Assingments", "All App Role Assingments", currentUser.Id, currentUser.Username, currentUser.Forename, currentUser.Surname, LogData, null);
        return new JsonResult(new { success = false, responseText = LogData });
    }

    return new JsonResult(new { success = true, responseText = "Succesfull :)" });
}

enter image description here

Example 2 - Using MS Graph REST Call

In a previous revision of my app I was fetching the AppRoles for the current service principal using a REST Call directly and the below does work in that scenario.

The code below was from a backed MS Graph microservice where I connected to the MS Graph using NET Core 5 as a daemon app. see https://learn.microsoft.com/en-us/azure/active-directory/develop/scenario-daemon-overview

You should be able to test the below using Graph Explorer to save time...

/// <summary>
/// Get App Roles for the current service principal.
/// </summary>
/// <remarks>
/// This GET request is used for fetching the list of all app roles which this service principal has been assigned.
/// 
/// | Parameter | Description |
/// | ------- | --------|
/// | servicePrincipal | The app's ObjectId string from Azure, see 'Enterprise Applications' in Azure Portal |
/// 
/// X-API-Version specifies the API version = 1.0
/// </remarks>
/// <response code="200">OK</response>
/// <response code="500">Internal Server Error</response>
[HttpGet, Route("getapproles/")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public async Task<ActionResult> GetAppRolesForCurrentServicePrincipal(string servicePrincipal)
{
    try
    {
        var uriString = $"{_graphApiUri}v1.0/servicePrincipals/{servicePrincipal}/appRoles";
        var graphApiResult = await _webApiCallRepo.CallWebApiWithGetRequest(uriString);
        // see https://makolyte.com/csharp-deserialize-json-to-dynamic-object/
        dynamic json = JsonConvert.DeserializeObject<ExpandoObject>(graphApiResult.Data, new ExpandoObjectConverter());
        int statusCode = (int)graphApiResult.StatusCode;
        return StatusCode(statusCode, json);
    }
    catch (Exception ex)
    {
        LogExtension logExtension = new LogExtension(_config);
        string logData = "MsGraph-API encountered an exception when fetching all app roles from the Microsoft Graph API for the current service principal.";
        logExtension.WriteLogEvent("Error", "App Roles", "Get App Roles", "All App Roles", logData, ex, _logger);
        return StatusCode(StatusCodes.Status500InternalServerError, ex);
    }
}

Example response:

enter image description here

Upvotes: 6

alphaz18
alphaz18

Reputation: 2766

Your best option is this endpoint: /servicePrincipals/{ID}/appRoleAssignedTo

https://learn.microsoft.com/en-us/graph/api/serviceprincipal-list-approleassignedto?view=graph-rest-1.0&tabs=http

this gives you a list of all the users who are assigned to the application with the ID of the app Role in there. there won't be a single call to have the app role name if thats what you're looking for. so you will have to make 2 calls. one to https://graph.microsoft.com/v1.0/servicePrincipals/ to get all the appRole names / ids, then the first call above to get the user assignment to those applications.

Upvotes: 8

Related Questions