Get Members from Delta Query on Groups - azure-active-directory

How do I return only Members from the delta API for group (https://learn.microsoft.com/en-us/graph/delta-query-overview?tabs=http)
Adding .Members & .Select() are not supported
await _graphServiceClient
.Groups
.Members
.Delta()
.Request()
.Filter($"id eq '{groupId}'")
.GetAsync();
On trying this:
var queryOptions = new List<QueryOption>()
{
new QueryOption("select", "members")
};
await _graphServiceClient
.Groups
.Delta()
.Request(queryOptions)
.Filter($"id eq '{groupId}'")
.GetAsync();
I see this error:
Message: Unrecognized query argument specified: 'select'. What am I missing?

Use Select method after Request.
var delta = await _graphServiceClient.Groups
.Delta()
.Request()
.Select("members")
.Filter($"id eq '{groupId}'")
.GetAsync();
in your example with QueryOption you are missing $ before select
var queryOptions = new List<QueryOption>()
{
new QueryOption("$select", "members")
};
await _graphServiceClient
.Groups
.Delta()
.Request(queryOptions)
.Filter($"id eq '{groupId}'")
.GetAsync();

You can try with below code
var user = await graphClient.Groups["{group-id}"].Members
.Request( queryOptions )
.Header("ConsistencyLevel","eventual")
.Select("displayname,id")
.GetAsync();
You can refer docs for more info - https://learn.microsoft.com/en-us/graph/api/group-list-members?view=graph-rest-beta&tabs=csharp#example-4-use-search-and-odata-cast-to-get-user-membership-in-groups-with-display-names-that-contain-the-letters-pr-including-a-count-of-returned-objects
Hope this helps
Thanks

Related

Resource units used for a graph request

I have the following code to find the count of users in AAD group:
var requestUrl = _graphClient.Groups[objectId.ToString()].TransitiveMembers.Request().RequestUrl;
requestUrl = $"{requestUrl}/microsoft.graph.user/$count";
var hrm = new HttpRequestMessage(HttpMethod.Get, requestUrl);
hrm.Headers.Add("ConsistencyLevel", "eventual");
await _graphServiceClient.AuthenticationProvider.AuthenticateRequestAsync(hrm);
var r = await _graphServiceClient.HttpProvider.SendAsync(hrm);
var content = await r.Content.ReadAsStringAsync();
var userCount = int.Parse(content);
return userCount;
Is there a way to find out the resource units used for this request (https://learn.microsoft.com/en-us/graph/throttling-limits)
According to the documentation, the resource unit cost for GET groups/{id}/transitiveMembers is 5.
But using $count affects the cost. If you send the request
GET https://graph.microsoft.com/v1.0/groups/{group_id}/transitivemembers/microsoft.graph.user/$count
and check the response headers there should be header x-ms-resource-unit which indicates the resource unit cost used for this request and it's 1.
Get header x-ms-resource-unit
var r = await _graphServiceClient.HttpProvider.SendAsync(hrm);
var cost = r.Headers.GetValues("x-ms-resource-unit").FirstOrDefault();

Get count of users while reading from AAD [Microsoft Graph]

I was following this documentation https://learn.microsoft.com/en-us/graph/aad-advanced-queries?tabs=csharp to run some graph query on AAD objects as follows:
await _graphServiceClient
.Users.Request()
.Request(new Option[] { new QueryOption("$count", "true") })
.Header("ConsistencyLevel", "eventual")
.Filter("endsWith(mail,'tenant.com')")
.GetAsync();
I see the following error:
What am I missing and how do I resolve the same?
await _graphServiceClient
.Users.Request(new Option[] { new QueryOption("$count", "true") })
.Header("ConsistencyLevel", "eventual")
.Filter("endsWith(mail,'tenant.com')")
.GetAsync();
I tried to reproduce the same in my environment and got the below results:
To retrieve the list of users with Mail-ID, I executed the below query in Microsoft Graph Explorer:
GET https://graph.microsoft.com/v1.0/users?$count=true&$filter=endsWith(mail,'#tenant.com')
ConsistencyLevel:eventual
Response:
You can make use of the below sample CSharp code:
GraphServiceClient graphClient = new GraphServiceClient( authProvider );
var queryOptions = new List<QueryOption>()
{
new QueryOption("$count", "true")
};
var users = await graphClient.Users
.Request( queryOptions )
.Header("ConsistencyLevel","eventual")
.Filter("endsWith(mail,'#tenant.com')")
.GetAsync();

call graph as part of authentication to add claims .net 4.5

i think the correct place is in SecurityTokenValidated but account is always null. i dont know how to set up the graphclient here?
SecurityTokenValidated = async (x) =>
{
IConfidentialClientApplication clientApp2 = MsalAppBuilder.BuildConfidentialClientApplication();
AuthenticationResult result2 = null;
var account = await clientApp2.GetAccountAsync(ClaimsPrincipal.Current.GetMsalAccountId());
string[] scopes = { "User.Read" };
// try to get an already cached token
result2 = await clientApp2.AcquireTokenSilent(scopes, account).ExecuteAsync().ConfigureAwait(false);
var graphClient = new GraphServiceClient(
new DelegateAuthenticationProvider(async (request) =>
{
//var token = await tokenAcquisition
// .GetAccessTokenForUserAsync(GraphConstants.Scopes, user: context.Principal);
var token = result2.AccessToken;
request.Headers.Authorization =
new AuthenticationHeaderValue("Bearer", token);
})
);
var user = await graphClient.Me.Request()
.Select(u => new
{
u.DisplayName,
u.Mail,
u.UserPrincipalName
})
.GetAsync();
var identity = x.AuthenticationTicket.Identity;
identity.AddClaim(new Claim(ClaimTypes.Role, "test"));
}
Please refer to this sample: https://learn.microsoft.com/en-us/samples/azure-samples/active-directory-dotnet-admin-restricted-scopes-v2/active-directory-dotnet-admin-restricted-scopes-v2/
You could follow this sample to get access token with GetGraphAccessToken() and make sure the signed-in user is a user account in your Azure AD tenant. Last thing is using Chrome in incognito mode this helps ensure that the session cookie does not get in the way by automatically logging you in and bypassing authentication.
This sample will not work with a Microsoft account (formerly Windows
Live account). Therefore, if you signed in to the Azure portal with a
Microsoft account and have never created a user account in your
directory before, you need to do that now. You need to have at least
one account which is a directory administrator to test the features
which require an administrator to consent.
var graphserviceClient = new GraphServiceClient(
new DelegateAuthenticationProvider(
(requestMessage) =>
{
// Get a token for the Microsoft Graph
var access_token = await GetGraphAccessToken();
requestMessage.Headers.Authorization = new AuthenticationHeaderValue("bearer", access_token);
return Task.FromResult(0);
}));
}
private async Task<string> GetGraphAccessToken()
{
IConfidentialClientApplication cc = MsalAppBuilder.BuildConfidentialClientApplication();
var userAccount = await cc.GetAccountAsync(ClaimsPrincipal.Current.GetMsalAccountId());
AuthenticationResult result = await cc.AcquireTokenSilent(new string[] { "user.read" }, userAccount).ExecuteAsync();
return result.AccessToken;
}

Count of users in AAD group

Is there a Microsoft Graph API to find out the number of users in an AAD group? Currently, here is my code on how I find it out. Curious to know if there is a quicker way?
private async Task<int> GetUserIds(string groupId)
{
List<string> userIds = new List<string>();
var usersFromGroup = await _groupMembersService.GetGroupMembersPageByIdAsync(groupId);
usersFromGroup.AdditionalData.TryGetValue("#odata.nextLink", out object nextLink);
var nextPageUrl = (nextLink == null) ? string.Empty : nextLink.ToString();
userIds.AddRange(usersFromGroup.OfType<Microsoft.Graph.User>().Select(x => x.Id));
while (!string.IsNullOrEmpty(nextPageUrl))
{
usersFromGroup = await _groupMembersService.GetGroupMembersNextPageAsnyc(usersFromGroup, nextPageUrl);
usersFromGroup.AdditionalData.TryGetValue("#odata.nextLink", out object nextLink2);
nextPageUrl = (nextLink2 == null) ? string.Empty : nextLink2.ToString();
userIds.AddRange(usersFromGroup.OfType<Microsoft.Graph.User>().Select(x => x.Id));
}
return userIds.Count;
}
}
public async Task<IGroupTransitiveMembersCollectionWithReferencesPage>GetGroupMembersPageByIdAsync(string groupId)
{
return await this.graphServiceClient
.Groups[groupId]
.TransitiveMembers
.Request()
.Top(this.MaxResultCount)
.WithMaxRetry(this.MaxRetry)
.GetAsync();
}
public async Task<IGroupTransitiveMembersCollectionWithReferencesPage> GetGroupMembersNextPageAsnyc(
IGroupTransitiveMembersCollectionWithReferencesPage groupMembersRef,
string nextPageUrl)
{
groupMembersRef.InitializeNextPageRequest(this.graphServiceClient, nextPageUrl);
return await groupMembersRef
.NextPageRequest
.GetAsync();
}
You can use this graph API to get the count for any Group.
https://graph.microsoft.com/v1.0/groups/{group-object-id}/members/$count
Make sure to add the ConsistencyLevel = Eventual in request headers for this.
Tested this in Graph Explorer for you :

SAML2.0 Access token using 'itfoxtec-identity-saml2'

I am trying to use your Nuget package for dotnet core and I get little bit success also I can login to SAML identity providers like Onelogin,Okta and I got loggin user information also But I am confuse while generating access token(Bearer token to call APIs of SAML identity providers). How will I get that token?
I can see securitytoken object in saml2AuthnResponse but don’t know how to that token and in that object security key and singin key is null.
I am totally new to this so may be I misunderstand something.
Please help me.
[Route("AssertionConsumerService")]
public async Task<IActionResult> AssertionConsumerService()
{
var binding = new Saml2PostBinding();
var saml2AuthnResponse = new Saml2AuthnResponse(config);
binding.ReadSamlResponse(Request.ToGenericHttpRequest(), saml2AuthnResponse);
if (saml2AuthnResponse.Status != Saml2StatusCodes.Success)
{
throw new AuthenticationException($"SAML Response status: {saml2AuthnResponse.Status}");
}
binding.Unbind(Request.ToGenericHttpRequest(), saml2AuthnResponse);
await saml2AuthnResponse.CreateSession(HttpContext, claimsTransform: (claimsPrincipal) => ClaimsTransform.Transform(claimsPrincipal));
var relayStateQuery = binding.GetRelayStateQuery();
var returnUrl = relayStateQuery.ContainsKey(relayStateReturnUrl) ? relayStateQuery[relayStateReturnUrl] : Url.Content("~/");
return Redirect(returnUrl);
}
You can get access to the SAML 2.0 token as a XML string by setting Saml2Configuration.SaveBootstrapContext = true in appsettings.json:
...
"Saml2": {
"SaveBootstrapContext": true,
"IdPMetadata": "https://localhost:44305/metadata",
"Issuer": "itfoxtec-testwebappcore",
...
}
Alternatively you can set the configuration in code:
config.SaveBootstrapContext = true;
Then you can read the SAML 2.0 token as a XML string in the saml2AuthnResponse.ClaimsIdentity.BootstrapContext:
public async Task<IActionResult> AssertionConsumerService()
{
var binding = new Saml2PostBinding();
var saml2AuthnResponse = new Saml2AuthnResponse(config);
binding.ReadSamlResponse(Request.ToGenericHttpRequest(), saml2AuthnResponse);
if (saml2AuthnResponse.Status != Saml2StatusCodes.Success)
{
throw new AuthenticationException($"SAML Response status: {saml2AuthnResponse.Status}");
}
binding.Unbind(Request.ToGenericHttpRequest(), saml2AuthnResponse);
await saml2AuthnResponse.CreateSession(HttpContext, claimsTransform: (claimsPrincipal) => ClaimsTransform.Transform(claimsPrincipal));
var samlTokenXml = saml2AuthnResponse.ClaimsIdentity.BootstrapContext as string;
var relayStateQuery = binding.GetRelayStateQuery();
var returnUrl = relayStateQuery.ContainsKey(relayStateReturnUrl) ? relayStateQuery[relayStateReturnUrl] : Url.Content("~/");
return Redirect(returnUrl);
}

Resources