7

I am authenticating users of my web api against Azure Active Directory. Now I want to get a list of groups that this user belongs.

I changed application manifest to include

"groupMembershipClaims": "All",

but all this does is to add claim hasGroups but no group names.

I granted all (8) Delegated Permissions to Windows Azure Active Directory for my app in the portal.

jlp
  • 9,800
  • 16
  • 53
  • 74
  • The "hasGroups" claim gets added when the user is part of more than 5 groups, even though that doesn't appear to be documented anywhere. 5 or fewer and you'll get a handful of "groups" claims with the object id of the group. – MattGWagner Sep 27 '18 at 15:50

4 Answers4

9

I've done exactly this.

Let's call my Azure AD appication "AD-App".

AD-App

Permissions to other applications is set to;

Windows Azure Active Directory.

Application Permissions: 0.

Delegated Permissions 2 ("Read directory data", "Sign in and read user profile".

Manifest has the following setting:

"groupMembershipClaims": "SecurityGroup"

Backend API

The following is my method to return the users groups. Either you send in the users id, if not it uses the id from claims. Id meaning "objectIdentifier".

        public static IEnumerable<string> GetGroupMembershipsByObjectId(string id = null)
    {
        if (string.IsNullOrEmpty(id))
            id = ClaimsPrincipal.Current.FindFirst("http://schemas.microsoft.com/identity/claims/objectidentifier").Value;

        IList<string> groupMembership = new List<string>();
        try
        {
            ActiveDirectoryClient activeDirectoryClient = ActiveDirectoryClient;
            IUser user = activeDirectoryClient.Users.Where(u => u.ObjectId == id).ExecuteSingleAsync().Result;
            var userFetcher = (IUserFetcher)user;

            IPagedCollection<IDirectoryObject> pagedCollection = userFetcher.MemberOf.ExecuteAsync().Result;
            do
            {
                List<IDirectoryObject> directoryObjects = pagedCollection.CurrentPage.ToList();
                foreach (IDirectoryObject directoryObject in directoryObjects)
                {
                    if (directoryObject is Group)
                    {
                        var group = directoryObject as Group;
                        groupMembership.Add(group.DisplayName);
                    }
                }
                pagedCollection = pagedCollection.GetNextPageAsync().Result;
            } while (pagedCollection != null);

        }
        catch (Exception e)
        {
            ExceptionHandler.HandleException(e);
            throw e;
        }

        return groupMembership;
    }

I can't tell you wether this is done by best practice or not, but it works for me.

Jonas
  • 146
  • 7
  • 1
    An important note for any readers of this: the Backend API method as it's written does not retrieve transitive group memberships. The former method via AD portal configuration does. – Alex Marshall Dec 10 '16 at 18:23
  • 1
    Thanks Worked for me :-) – Saurabh Mar 20 '17 at 17:43
  • 1
    It would be nice if you included the necessary namespaces in the above example. – LarryBud Jan 23 '18 at 19:29
  • @LarryBud yeah sorry about that, I will try to remember to do that another time. Not sure I can find this project again, but if I do I'll update my answer! Thanks! – Jonas Jan 25 '18 at 08:00
  • @Jonas, when you said the above method is the Backend API method, do you mean you run it in Azure somehow (I'm new to Azure, so got a lot to learn)? Or is it run in something like a MVC controller? – Rod May 23 '18 at 21:00
  • 1
    @Rod - Holy moly, this is so long ago I can't say for sure! But, I do believe it was a WebAPI project running as a Azure Web App at the time :) Hope it helps! – Jonas May 25 '18 at 14:33
  • Talking about namespaces, just to let you know in order to use that piece of code you have to install the following NUGET Package https://www.nuget.org/packages/Microsoft.Azure.ActiveDirectory.GraphClient – LeoGranata Jun 29 '18 at 18:03
  • 3
    `ActiveDirectoryClient activeDirectoryClient = ActiveDirectoryClient` this line doesn't work. – Vasyl Zvarydchuk Jul 16 '18 at 21:38
3

Here is what we did in a project:

Sign in to https://portal.azure.com and click on Azure Active Directory -> App registrations -> <YOUR_APP> -> Manifest and set groupMembershipClaims to 7. You can read more about this here:

https://learn.microsoft.com/en-us/azure/active-directory/develop/active-directory-application-manifest

You can then access the user groups like this:

[Route("api/[controller]")]
[ApiController]
public class CurrentUserController : ControllerBase
{
    [HttpGet("groups")]
    [ProducesResponseType(typeof(IEnumerable<ClaimsViewModel>), (int)HttpStatusCode.OK)]
    public IActionResult Groups()
    {
        return Ok(User.Claims.Where(claim => claim.Type == "groups").Select(c => new ClaimsViewModel() { Type = c.Type, Value = c.Value }));
    }
}

public class ClaimsViewModel
{
    public string Type { get; set; }
    public string Value { get; set; }
}

Sample respons with fake Object IDs:

[{"type":"groups","value":"12fef9e0-4b73-425d-91b7-30c027aa4945"},{"type":"groups","value":"12fef9e0-4b73-425d-91b7-30c027aa4946"},{"type":"groups","value":"12fef9e0-4b73-425d-91b7-30c027aa4947"},{"type":"groups","value":"12fef9e0-4b73-425d-91b7-30c027aa4948"},{"type":"groups","value":"12fef9e0-4b73-425d-91b7-30c027aa4949"}]

Given these IDs you can then identify the groups in AD.

Ogglas
  • 62,132
  • 37
  • 328
  • 418
  • 3
    Big caveat here: if the user is in more than 5 groups, they will only get the "hasGroups" claim that the OP mentions "to limit token size." Ran into this unexpectedly. – MattGWagner Sep 27 '18 at 15:49
1

If a user has more than 150 groups, only the link to Graph API in a calim like "graph:link" is returned and not the groups. It is done for performance reasons. You then need to call Graph API (MS Graph API - newest, or AD Graph API - older) to iterated through all groups.

mfralou
  • 826
  • 6
  • 5
0

What permissions did you grant to your app? You need to explicitly request the ability to read groups (see group.read.all in https://msdn.microsoft.com/en-us/library/azure/ad/graph/howto/azure-ad-graph-api-permission-scopes). As of today, those permissions can only be consented by an administrator.

vibronet
  • 7,364
  • 2
  • 19
  • 21