A look behind the Azure AD “Permission classifications” preview

For a long time, Azure AD has been criticized for having a too liberal approach to user consents by default, with users being able to delegate things like “Mail.ReadWrite” allowing apps to send and receive emails, as well as reading any existing emails, and “User.ReadBasic.All” allowing your users to consent to third party applications reading ALL of your users basic profiles. Combine this with the “offline_access” scope, where the 3rd party apps can essentially retain access after the user has logged out of the app, this soon becomes a bit of a nightmare.

Microsoft has made several features available to help mitigate the risk of these illicit or “rouge” consents. A year ago, they launched the “admin consent workflow” preview, where you could disallow your users from directly consenting to applications, but instead requiring them to request an administrator to consent on their behold. The administrator of course needing to have “some” knowledge of what they consent to.

With an admin consent workflow configured, a pre-set list of admins can be defined, that receives all requests for consent.

Configure admin consent workflow settings

What I find really interesting behind the scenes, is that when you save this policy, what actually happens is that the following REST API call happens toward the Azure AD API for the Azure Portal:

POST https://main.iam.ad.ext.azure.com/api/RequestApprovals/V2/PolicyTemplates

{
"id": null,
"requestExpiresInDays": 30,
"notificationsEnabled": true,
"remindersEnabled": true,
"approvers": [
"013c0b64-166d-4a10-8653-bf003addc291"
]
}

And with the following response, we can actually see that a “Request approval” or “Policy template” has been created:

{
    "id": "26a38547-eec2-473f-986a-fd9bc302d232",
    "approvers": [
        "013c0b64-166d-4a10-8653-bf003addc291"
    ],
    "requestExpiresInDays": 30,
    "notificationsEnabled": true,
    "remindersEnabled": true
}

After this, we also see a patch happening towards a “settings” object:

PATCH https://main.iam.ad.ext.azure.com/api/MsGraph/beta/settings/cc7fa9fc-45f6-4dcc-bde5-f3d8297d2491

{
    "values": [
        {
            "name": "EnableGroupSpecificConsent",
            "value": "true"
        },
        {
            "name": "BlockUserConsentForRiskyApps",
            "value": "true"
        },
        {
            "name": "EnableAdminConsentRequests",
            "value": "true"
        },
        {
            "name": "ConstrainGroupSpecificConsentToMembersOfGroupId",
            "value": ""
        }
    ]
}

We can actually work with the Graph Beta to get this same setting using the url https://graph.microsoft.com/beta/settings/. What I believe we are seeing here is traces of what will come – more granular admin consent workflows. I expect that we will at some point be able to create several “Request approval workflows”, where we can either target groups of users for which admins can consent on their behold, or certain risk levels (we are coming to this topic soon) can be mapped to different admins, depending on expertise or access level.

Navigating over to the “Permission classifications” pane, we can define certain permissions that we allow our users to consent to on their own, without administrator involvement.

Here you can define any API that are publishing scopes to your Azure AD tenant, and again, let’s check what happens behind the scenes, in order to look into the future.

First we see a query for servicePrincipals, using an undocumented filter only attribute hasPermissionClassifications for filter and and another undocumented attribute delegatedPermissionClassification as a reference to classifications.

GET https://main.iam.ad.ext.azure.com/api/MsGraph/beta/servicePrincipals?$filter=hasPermissionClassifications%20eq%20true&$expand=delegatedPermissionClassification

{
    "@odata.context": "https://graph.microsoft.com/beta/$metadata#servicePrincipals(delegatedPermissionClassifications())",
    "value": [
        {
            "id": "9a526646-15be-4c0f-878f-84f07ee3f795",
            "appDisplayName": "Microsoft Graph",
            "appId": "00000003-0000-0000-c000-000000000000",
            "appOwnerOrganizationId": "f8cdef31-a31e-4b4a-93e4-5f571e91255a",
            "displayName": "Microsoft Graph",
            "publisherName": "Microsoft Services",
            "servicePrincipalNames": [
                "https://graph.microsoft.com"
            ],
            "servicePrincipalType": "Application",
            "signInAudience": "AzureADMultipleOrgs",
            "appRoles": [
                {
                    "allowedMemberTypes": [
                        "Application"
                    ],
                    "description": "Allows the app to read role-based access control (RBAC) settings for all RBAC providers without a signed-in user. This includes reading role definitions and role assignments.",
                    "displayName": "Read role management data for all RBAC providers",
                    "id": "c7fbd983-d9aa-4fa7-84b8-17382c103bc4",
                    "isEnabled": true,
                    "origin": "Application",
                    "value": "RoleManagement.Read.All"
                },
                .......,
                {
                    "adminConsentDescription": "Allows the app to read email in the signed-in user's mailbox except body, previewBody, attachments and any extended properties.",
                    "adminConsentDisplayName": "Read user basic mail",
                    "id": "a4b8392a-d8d1-4954-a029-8e668a39a170",
                    "isEnabled": true,
                    "type": "User",
                    "userConsentDescription": "Allows the app to read email in the signed-in user's mailbox except body, previewBody, attachments and any extended properties.",
                    "userConsentDisplayName": "Read user basic mail",
                    "value": "Mail.ReadBasic"
                }
            ],
            "delegatedPermissionClassifications@odata.context": "https://graph.microsoft.com/beta/$metadata#servicePrincipals('9a526646-15be-4c0f-878f-84f07ee3f795')/delegatedPermissionClassifications",
            "delegatedPermissionClassifications": [
                {
                    "id": "6eAndLov_kKwwISMnmqBggE",
                    "permissionId": "7427e0e9-2fba-42fe-b0c0-848c9e6a8182",
                    "permissionName": "offline_access",
                    "classification": "low"
                },
                {
                    "id": "1s2mZLGqr0qUuDzIQF6Q0AE",
                    "permissionId": "64a6cdd6-aab1-4aaf-94b8-3cc8405e90d0",
                    "permissionName": "email",
                    "classification": "low"
                },
                {
                    "id": "NfL3N3xSNkGszUoC0ZcpbgE",
                    "permissionId": "37f7f235-527c-4136-accd-4a02d197296e",
                    "permissionName": "openid",
                    "classification": "low"
                },
                {
                    "id": "2G3-4TG6YU2J54hjnaRoPQE",
                    "permissionId": "e1fe6dd8-ba31-4d61-89e7-88639da4683d",
                    "permissionName": "User.Read",
                    "classification": "low"
                },
                {
                    "id": "ntbaFJsJyUKBC9ACmB_uwQE",
                    "permissionId": "14dad69e-099b-42c9-810b-d002981feec1",
                    "permissionName": "profile",
                    "classification": "low"
                }
            ]
        }
    ]
}

Here too we can query the regular Graph Beta using the following url: https://graph.microsoft.com/beta/servicePrincipals?$expand=delegatedPermissionClassifications&$select=id,appid&$filter=hasPermissionClassifications eq true.

What I find most interesting here is the classification property, which currently only has the value of “low”. The documentation states that “low” is currently the only supported value.

Over to the “User consent settings” page:

Again, going behind the scenes, we see a query for authorizationPolicy objects:

GET https://main.iam.ad.ext.azure.com/api/MsGraph/beta/policies/authorizationPolicy/authorizationPolicy?$select=permissionGrantPolicyIdsAssignedToDefaultUserRole

{
"@odata.context": "https://graph.microsoft.com/beta/$metadata#policies/authorizationPolicy",
"value": [
{
"permissionGrantPolicyIdsAssignedToDefaultUserRole": [
"microsoft-user-default-low"
]
}
]
}

Nothing new about this endpoint, it is available in the Graph Beta here, and even has documentation. The value of “microsoft-user-default-low” is as far as I have seen only used here, but seems to point to a policy object that we might be able to have several instances of at some point in the future.

I didn’t really find any super interesting discoveries behind the scenes here, but it is interesting to see where Microsoft is “probably” going with Azure AD.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s