I am working on .net core project. I am trying to implement authorize using AD groups. My requirement is, I have many groups in the azure ad. If the current user belongs to any of the available groups in azure ad then I want to authorize those users to access apis written in .net core application. I tried as below. I have added below two classes
public class IsMemberOfGroupHandler : AuthorizationHandler<IsMemberOfGroupRequirement>
{
protected override Task HandleRequirementAsync(
AuthorizationHandlerContext context, IsMemberOfGroupRequirement requirement)
{
var groupClaim = context.User.Claims
.FirstOrDefault(claim => claim.Type == "groups" &&
claim.Value.Equals(requirement.GroupId, StringComparison.InvariantCultureIgnoreCase));
if (groupClaim != null)
context.Succeed(requirement);
return Task.CompletedTask;
}
}
public class IsMemberOfGroupRequirement : IAuthorizationRequirement
{
public readonly string GroupId;
public readonly string GroupName;
public IsMemberOfGroupRequirement(string groupName, string groupId)
{
GroupName = groupName;
GroupId = groupId;
}
}
Below is my startup class.
services.AddAuthorization(options =>
{
var adGroupConfig = new List<AdGroupConfig>();
_configuration.Bind("AdGroups", adGroupConfig);
foreach (var adGroup in adGroupConfig)
options.AddPolicy(
adGroup.GroupName,
policy =>
policy.AddRequirements(new IsMemberOfGroupRequirement(adGroup.GroupName, adGroup.GroupId)));
});
Above code checks groups available in configuration file. Now my requirement is use microsoft graph api to get all the available groups. I could not find any way to handle this requirement. Can someone help me with this? Any help would be appreciated. Thanks
Please firstly check this code sample , which use OpenID Connect to sign in users and use MSAL to get the Microsoft Graph API token to retire groups .
If config the your application to receive group claims by editing the manifest :
{
...
"errorUrl": null,
"groupMembershipClaims": "SecurityGroup",
...
}
The object id of the security groups the signed in user is member of is returned in the groups claim of the token.
If a user is member of more groups than the overage limit (150 for SAML tokens, 200 for JWT tokens), then the Microsoft Identity Platform does not emit the groups claim in the token. Instead, it includes an overage claim in the token that indicates to the application to query the Graph API to retrieve the user’s group membership.
{
...
"_claim_names": {
"groups": "src1"
},
{
"_claim_sources": {
"src1": {
"endpoint":"[Graph Url to get this user's group membership from]"
}
}
...
}
So you can follow the process :
Check for the claim _claim_names with one of the values being groups. This indicates overage.
If found, make a call to the endpoint specified in _claim_sources to fetch user’s groups.
If none found, look into the groups claim for user’s groups.
Of course , you can directly call Microsoft Graph API to retire current user's groups without using group claims
:
https://docs.microsoft.com/en-us/graph/api/user-list-memberof?view=graph-rest-1.0&tabs=http
You can then authorize based on that groups . For example , if using policy :
services.AddAuthorization(options =>
{
options.AddPolicy("GroupsCheck", policy =>
policy.Requirements.Add(new GroupsCheckRequirement("YourGroupID")));
});
services.AddScoped<IAuthorizationHandler, GroupsCheckHandler>();
GroupsCheckRequirement.cs:
public class GroupsCheckRequirement : IAuthorizationRequirement
{
public string groups;
public GroupsCheckRequirement(string groups)
{
this.groups = groups;
}
}
GroupsCheckHandler.cs :
public class GroupsCheckHandler : AuthorizationHandler<GroupsCheckRequirement>
{
private readonly ITokenAcquisition tokenAcquisition;
private readonly IMSGraphService graphService;
public GroupsCheckHandler(ITokenAcquisition tokenAcquisition, IMSGraphService MSGraphService)
{
this.tokenAcquisition = tokenAcquisition;
this.graphService = MSGraphService;
}
protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context,
GroupsCheckRequirement requirement)
{
string accessToken = await tokenAcquisition.GetAccessTokenOnBehalfOfUserAsync(new[] { Constants.ScopeUserRead, Constants.ScopeDirectoryReadAll });
User me = await graphService.GetMeAsync(accessToken);
IList<Group> groups = await graphService.GetMyMemberOfGroupsAsync(accessToken);
var result = false;
foreach (var group in groups)
{
if (requirement.groups.Equals(group.Id))
{
result = true;
}
}
if (result)
{
context.Succeed(requirement);
}
}
}
And then using policy :
[Authorize(Policy = "GroupsCheck")]
You can use this graph api to get all the groups the user is a direct member of.
GET /me/memberOf
In .net-core you can use GraphServiceClient to call graph api. Here is a sample for your reference.
var graphClient = new GraphServiceClient(
new DelegateAuthenticationProvider(
(requestMessage) =>
{
// Get back the access token.
var accessToken = "";
if (!String.IsNullOrEmpty(accessToken))
{
// Configure the HTTP bearer Authorization Header
requestMessage.Headers.Authorization = new AuthenticationHeaderValue("bearer", accessToken);
}
else
{
throw new Exception("Invalid authorization context");
}
return (Task.FromResult(0));
}
));
var groups = graphClient.Me.MemberOf.Request().GetAsync().Result;