Azure Active Directory application model
- 1/22/2016
Groups
In closing this chapter about how Azure AD models applications, I am going to show you how to work with groups. Groups in Azure AD can be cloud-only sets of users, created and populated via the Azure portal or the Office 365 portal, or they can be synched from on-premises distribution lists and security groups. Groups have been a staple of access control for the last few decades. As a developer, you can count on groups to work across applications and to be assigned and managed by administrators: all you need to know is that a group exists and what its semantic is and then use that information to drive your app’s decisions regarding the current user (access control, UI customization, and so on).
By default, tokens issued by Azure AD do not carry any group information: if your app is interested in which groups the current user belongs to, it has to use the Directory Graph API (cue the next chapter).
Just as with application roles, you can ask Azure AD to start sending group information in issued tokens in the form of claims—simply by flipping a switch property in the Application object. If you download your app manifest, modify the groupMembershipClaims property as follows, and then upload the manifest again, you will get group information in the incoming tokens:
"groupMembershipClaims": "All",
If you are interested in receiving just the security groups, enter “SecurityGroup” instead of “All”.
After changing the manifest as described, I used the portal to create in my test tenant a new group called “Hippies,” and assigned to it the test user Fabio. That done, I launched the app and signed in as Fabio. Here’s the token I got:
{ "amr" : [ "pwd" ], "aud" : "c3d5b1ad-ae77-49ac-8a86-dd39a2f91081", "c_hash" : "zit-F66pwRsDeJPtjpuzgA", "exp" : 1442822854, "family_name" : "Bianchi", "given_name" : "Fabio", "groups" : [ "d6f48969-725d-4869-a7a0-97956001d24e" ], "iat" : 1442818954, "iss" : "https://sts.windows.net/6c3d51dd-f0e5-4959-b4ea-a80c4e36fe5e/", "name" : "Fabio Bianchi", "nbf" : 1442818954, "nonce" : "635784160492173285.ZmIyMTM5NGYtZDEyNC00MThmLTgyN2YtNTZkNzViZjA1MDgxMzljZDA1OWMtNjV hOC00ZWI1LThkNmQtZDE4NGJlOTU2ZGZj", "oid" : "a21197f6-5ac6-460b-b5d3-2a1ae6bd08c1", "sub" : "0vmQvSCoJqTYby1EE0XR94PgRuveuOWUbAHNkmf0xTk", "tid" : "6c3d51dd-f0e5-4959-b4ea-a80c4e36fe5e", "unique_name" : "fabio@developertenant.onmicrosoft.com", "upn" : "fabio@developertenant.onmicrosoft.com", "ver" : "1.0" }
You can see that there is indeed a groups claim, but what happened to the group name? Well, the short version of the story is that because Azure AD is a multitenant system, arbitrary group names like “People in building 44” or “Hippies” have no guarantee of being unique. Hence, if you wrote code relying on only a group name, your code would often be broken and subject to misuse (a malicious admin might create a group matching the name you expect in a fraudulent tenant and abuse your access control logic). As a result, today Azure AD sends only the objectId of the group. You can use that ID for constructing the URI of the group itself in the directory, in this case that’s:
https://graph.windows.net/developertenant.onmicrosoft.com/groups/d6f48969-725d-4869-a7a0- 97956001d24e.
In the next chapter, you’ll learn how to use the Graph API to use that URI to retrieve the actual group description, which in my case looks like the following:
{ "odata.metadata": "https://graph.windows.net/developertenant.onmicrosoft. com/$metadata#directoryObjects/Microsoft.DirectoryServices.Group/@Element", "odata.type": "Microsoft.DirectoryServices.Group", "objectType": "Group", "objectId": "d6f48969-725d-4869-a7a0-97956001d24e", "deletionTimestamp": null, "description": "Long haired employees", "dirSyncEnabled": null, "displayName": "Hippies", "lastDirSyncTime": null, "mail": null, "mailNickname": "363bdd6b-f73c-43a4-a3b4-a0bf8b528ee1", "mailEnabled": false, "onPremisesSecurityIdentifier": null, "provisioningErrors": [], "proxyAddresses": [], "securityEnabled": true }
Your app could query the Graph periodically to find out what group identifiers to expect, or you could perform queries on the fly as you receive the group information, though that would somewhat defeat the purpose of getting groups in the form of claims.
Consuming groups entails more or less the same operations described for roles and ClaimsPrincipal. You can even assign groups as the RoleClaimType if that’s the strategy you usually enact for groups (traditional IsInRole actually works against Windows groups on-premises, often creating a lot of confusion).
One last thing about groups. There are tenants in which administrators choose to use groups very heavily, resulting in each user belonging to very large numbers of groups. Adding many groups in a token would make the token itself too large to fulfil its usual functions (such as authentication and so on), so Azure AD caps at 200 the number of groups that can be sent via JWT format. If the user belongs to more than 200 groups, Azure AD does not pass any group claims; rather, it sends an overage claim that provides the app with the URI to use for retrieving the user’s groups information via the Graph API. Azure AD does so by following the OpenID Connect core specification for aggregated and distributed claims: in a nutshell, a mechanism for providing claims by reference instead of passing the values. Say that Fabio belonged to 201 groups in our sample above. Instead of the groups claims, the incoming JWT would have contained the following claims:
"_claim_names": { "groups": "src1", }, "_claim_sources": { "src1": {"endpoint": "https://graph.windows.net/developertenant.onmicrosoft.com/users/ a21197f6-5ac6-460b-b5d3-2a1ae6bd08c1/getMemberObjects"} }
In the next chapter, you’ll learn how to use that endpoint for extracting group information for the incoming user.