Azure B2C Tenant and Graph API, user management - azure

This is regarding an application where we are using Azure B2C tenant for authentication. There is a requirement to get lists of users which would support filtering, pagination and users have to be from a particular TenantId. We are using Graph API SDK that i.e., microsoft.graph and microsoft.graph.Auth packages.
Steps I have done
Created graph client with ClientCredentialProvider with TenantId.
Getting users using the below code
var users = await graphClient.Users
.Request()
.Top(100)
.Filter("identities/any(c:c/issuer eq 'contoso.onmicrosoft.com')")
.Select("displayName,id,identities")
.GetAsync();
This gets all users for a given issuer or tenant. Now, there is an issue I cannot filter users using this option .Filter("identities/any(c:c/issuer eq 'contoso.onmicrosoft.com') and startswith(displayName,'a') i.e., get all users whose display name starts with 'a' and belong to this issuer 'contoso.onmicrosoft.com'. As per Microsoft, Graph API does not currently support complex queries on Identities. They show this message Message: Complex query on property identities is not supported.
Now, right now my thoughts are limited to this option of loading entire user table for this tenant onto memory. I think this would be not the best approach, because we will have more tenants and I don't know how much users we can store in memory.
Anyone who has more understanding on these type of scenarios, please share your inputs. I wanted to know various other alternatives we could take.

As the message says, "Complex query on property identities is not supported", it's also not supported in Microsoft Graph SDK. You could only check the users with String.StartsWith() method in C#.
var users = await graphClient.Users
.Request()
.Top(100)
.Filter("identities/any(c:c/issuer eq 'contoso.onmicrosoft.com')")
.Select("displayName,id,identities")
.GetAsync();
List<User> userResult = new List<User>();
foreach(var user in users)
{
if (user.displayName.StartsWith(a)) {
userResult.add(user);
}
}

Related

Setting up an Application with Azure for use with Graph API outlook calendars

I'm aware that Graph API has a nice nuget package and I am confident on the code side of things, but my understanding is that I need to have the application set up in Azure and while there is a lot of documentation about this in general, I find it quite dense and I'm not confident I have the specifics down for how I need to set this portion up.
What I need my application to do is access an outlook calendar of a specific user that I own, read, search, add, delete and update calendar items. The integration assistant seems to suggest I need to configure a URI redirect and configure api permission. The default persmission is User.Read on graph API and if I try to add a permission, office 365 management seems like it might be the one I need except it specifically says just retrieving user information and nothing mentions outlook anywhere.
I need to know more or less the minimum steps in setting up the application in Azure to write a C# application that can make changes to outlook for a user.
need my application to do is access an outlook calendar of a specific user
Does it mean you need your app to have the abiltity to modify the callendar of any user you owned? If not, then it means you need your application to provide a sign in module and let users sign in, then the users can get authentication to call graph api and manage their own calendar, since this scenario, users give the delegate api permission, so they can't manage other users' calendar, so I don't think this is what you want.
If so, then you should use client credential flow to generate access token to call graph api. I think you know that when you want to call graph api, you have to get an access token which has correct permission first.
Ok, then let's come to the api permission, when you go to api document of the Calendar. You will see permissions like screenshot below:
Application permission type is suitable for client credential flow. And after viewing all the apis, you will find that they all need Calendars.ReadWrite except those not supporting Application type.
Then let's go to azure portal and reach Azure Active Directory. You need to create an Azure ad application and give the app Calendars.ReadWrite permission, then give the Admin consent.
Then you also need to create a client secret, pls go to Certificates & Secrets and add a new client secret, don't forget to copy the secret after you create it.
Now you've done all the steps. No need to set a redirect url, because you don't need to let the user to sign in your application. Let's see client credential flow document, it only require client_id, client_secret to generate access token.
Or in the code, you may use SDK like this :
using Azure.Identity;
using Microsoft.Graph;
public async Task<IActionResult> Index()
{
var scopes = new[] { "https://graph.microsoft.com/.default" };
var tenantId = "your_tenant_name.onmicrosoft.com";
var clientId = "azure_ad_app_id";
var clientSecret = "client_secret";
var clientSecretCredential = new ClientSecretCredential(
tenantId, clientId, clientSecret);
var graphClient = new GraphServiceClient(clientSecretCredential, scopes);
var calendar = new Calendar{ Name = "Volunteer" };
var events = await graphClient.Users["user_id_which_is_needed_to_list_calendar_events"].Events.Request()
.Header("Prefer","outlook.timezone=\"Pacific Standard Time\"")
.Select("subject,body,bodyPreview,organizer,attendees,start,end,location")
.GetAsync();
return View();
}

Calling MS Graph API for additional attribute from within B2C IEF Policy

I am trying to prevent duplicate accounts from being created in Azure B2C by looking at a custom field (i.e. Employee ID) and if there is a record of that Employee ID already existing, not allowing the user to create a new account. Since it doesn't appear you can use custom fields as an Input, I was considering using the Graph API to see if a record is returned for a given Employee ID- if it does, then it would stop the registration process, if it doesn't the registration can continue.
Is it possible to directly call the Graph API and do this record count comparison within a policy. Or would I need to have a separate script/function to call Graph API with the given employee ID and then return the number of records to compare?
During sign up, store the employeeId value in the signInNames attribute using a custom policy. This attribute has a uniqueness constraint.
You can acheive this using Microsoft Graph SDK.
Any request to the Microsoft Graph API requires an access token for authentication. The solution makes use of the Microsoft.Graph.Auth NuGet package that provides an authentication scenario-based wrapper of the Microsoft Authentication Library (MSAL) for use with the Microsoft Graph SDK.
For instance, you are using C# to achieve this, Program.cs code snippet will look like:
// Read application settings from appsettings.json (tenant ID, app ID, client secret, etc.)
AppSettings config = AppSettingsFile.ReadFromJsonFile();
// Initialize the client credential auth provider
IConfidentialClientApplication confidentialClientApplication = ConfidentialClientApplicationBuilder
.Create(config.AppId)
.WithTenantId(config.TenantId)
.WithClientSecret(config.ClientSecret)
.Build();
ClientCredentialProvider authProvider = new ClientCredentialProvider(confidentialClientApplication);
// Set up the Microsoft Graph service client with client credentials
GraphServiceClient graphClient = new GraphServiceClient(authProvider);
UserService.cs:
public static async Task ListUsers(GraphServiceClient graphClient)
{
Console.WriteLine("Getting list of users...");
// Get all users (one page)
var result = await graphClient.Users
.Request()
.Select(e => new
{
e.employeeId
})
.GetAsync();
foreach (var user in result.CurrentPage)
{
Console.WriteLine(JsonConvert.SerializeObject(user));
}
}
If you get result as an existing employee, you will invalidate the login and send error response with an error message.

Azure AD: How to make tokens have the "hasgroups" claim?

Our application allows assigning permission to groups, which means for every user, we have to reliably determine group membership. The user presents a token regularly obtained with ADAL (some use .NET, others use NodeJS, others use CLI).
Some users seem to be sending a token with the following claim:
"hasgroups": true,
That claim is documented in the Azure AD token reference page.
We would like to add a test case for that, but after following steps here and here, we always end up with a token with the following claims:
"_claim_names": {
"groups": "src1"
},
"_claim_sources": {
"src1": {
"endpoint": "https://graph.windows.net/{redacted}/users/{redacted}/getMemberObjects"
}
},
What is wrong with our setup? Why can't we get the hasgroups claim?
Here are some additional information:
Application type is Native (not WebApi).
Manifest says "oauth2AllowImplicitFlow": true.
The application is given access to Azure Key Vault.
We use the following code to get the token (in C#):
var userCredential = new UserCredential( _userName, _password );
result = context.AcquireToken( _resource, _clientId, userCredential );
Where:
_userName and _password are from a user with lots of groups.
_clientId is the application id of the native application - the one with "oauth2AllowImplicitFlow": true.
_resource is https://vault.azure.net.
The token is emitted correctly. The only issue is that it shows _claim_names and _claims_sources instead of hasgroups.
Where: • _userName and _password are from a user with lots of groups.
As the user is part of lots of groups (assuming 6 or more here).. Azure AD token will come back with a groups overage indicator instead of actual group ids in “groups” claim. I guess you know that and hence doing it intentionally.
var userCredential = new UserCredential( _userName, _password );
result = context.AcquireToken( _resource, _clientId, userCredential );
Since you're acquiring the token in a .NET based application using C# code, the token response is not really limited in length (like in cases for a web SPA, where it is being returned as a URI fragment and URL length has limits)
Looking at the documentation both "hasgroups" and "groups:src1" claims have the same intention of telling that there are too many groups to return as part of the token. Although there is a subtle difference:
in cases where URL limit applies, "hasgroups" will be sent as true (like implicit grant flow for SPA)
in cases where length is not limited (like in your case), Azure AD will still not return all the groups to make sure the token doesn't get too big, but it will send a little more information on how to get to all groups by sending the information on how you can query for all your groups. In this case it's sending the "groups:src1" and "_claim_sources" with source information instead of just the "hasgroups"
Claims in id_tokens
For anyone looking more on this. Please refer Doc saml-tokens
Note
Source : Azure Sample Link

Auth0 subscription plan app_metadata

I'm developing a quiz app which requires authorization for only-subscribed members can see.
How to do that? I'm thinking of putting metadata (is_subscribed) to true for subscribed member and give the scope so he/she can gain permissions.
But, I don't know how to do it. Please help. The docs is so confusing
There are two separate concerns here.
Where to keep the subscription information. app_metadata is fine, or you might choose to do so in a backend database (application specific). A client application will probably handle subscriptions and be in charge of updating that value. If you store the value in app_metadata, you will use Management API v2 to alter the user profile from the application that handles subscriptions.
Add an authorization scope based on the subscription status. In this case, you would use a rule to add a custom scope based on the value of the is_subscribed field. I.e.:
function(user, context, callback) {
if (user.app_metadata && user.app_metadata.is_subscribed) {
context.accessToken.scope = ['read:quiz'];
} else {
// remove the ability to read a quiz if not subscribed.
context.accessToken.scope = [];
}
callback(null, user, context);
}
If you decided to store the subscription information in a backend database instead of in the app_metadata, you would simply access the database from the rule in the above code.

Get the filtered activedirectoryclient.users from azure adfs using like

I am trying to get few users from Azure ADFS within my domain. I am able to get all of my users from my integrated Office 365. But my requirement is to get the filtered user lists. Can we do something like below, I have tried. But it doesn't return anything even if I have few users with that.
ActiveDirectoryClient activeDirectoryClient = new ActiveDirectoryClient(serviceRoot,
async () => await GetTokenForApplication());
var result0 = await activeDirectoryClient.Users
.Where(u => u.GivenName.Contains("sibeesh"))
.ExecuteAsync();
var result1 = await activeDirectoryClient.Users
.Where(u => SqlMethods.Like(u.DisplayName, "sib%"))
.ExecuteAsync();
And also how can we get the users from other domains which we have in our ADFS? How can we group those users accordingly. I am totally new to configuring ADFS, any help is much appreciated. Thanks in advance.
Just to get the terms right.
There is no such thing as Azure ADFS.
Azure AD is in the cloud. ADFS is on-premises and is not an Azure product.
You are using the Azure AD Graph API Client Library and there are some good examples of syntax here.
This client library does not talk to ADFS.
Azure AD does not have the concept of domains - rather tenants.
Please clarify "And also how can we get the users from other domains which we have in our ADFS?"

Resources