AAD hosted Blazor Webassembly - How to get subset of user's AD groups when user is member of large number of groups - azure-active-directory

I have asked this question on ASP.Net Core github repo, but I do not think my query was sufficiently answered, so posting the question here.
I followed the instructions here to get a user's AD groups as claims. However, the user is member of a large number of groups, and I just see a single claim "hasGroups".
My question is: what is the suggested best practice/pattern to follow in such cases, as I am interested in retrieving only a few of the user's groups that match a string pattern. Where would I even write the code to perform this filter?
I know how to code the graph api query, but where/when exactly to make this call is unclear. And once I retrieve the groups from Graph Api, how do I reflect the group information into the token claims, so the client app can use regular Authorization mechanism, without knowing the details of how the user's groups were populated.

I'm not sure if this is the recommended way of doing it, but the docs here talk about adding groups and roles to use the user object claims for blazor. https://learn.microsoft.com/en-us/aspnet/core/security/blazor/webassembly/azure-active-directory-groups-and-roles?view=aspnetcore-3.1
I'm not sure if it's even possible, but in the customuserfactory, I would try to replace the
foreach (var group in account.Groups)
{
userIdentity.AddClaim(new Claim("group", group));
}
with some code to try to call the graph api (somehow get the token to call the api with, that's the part I'm not sure on), parse the groups and add them to the user claims,
then follow the rest of the example of how to incorporate that into the [authorize] mechanism.
again, I'm not super familiar with blazor wasm yet, and I couldn't find any docs other than this to add groups/roles into the authorization mechanism.
if anyone else has a better method of doing it or why this wouldn't work feel free to chime in, but I hope that this can at least give you some ideas and is slightly useful.

Related

Best practise for populating access token with external claims

We have implemented IdSrv4 on top of AspNetCore Identity and we use ADFS as external IdP. From ADFS we wan´t to get the users AD-groups, upn and som other claims. The claims will be used both inside our IdSrv4 implementation, but will also be sent to our API-resources as part of the access token.
The current situation in our IdSrv4 implementation:
ADFS has been configured so that it emits the claims that we want and in our IdSrv4 implementation those claims are received as expected in the "ExternalLoginCallback" method of the AccountController.
IProfileService has been implemented in order to fill the "IssuedClaims" list with claims.
BUT, I haven't managed to build the connection between those to steps. What is the preferred way to preserve the claims received in "ExternalLoginCallback" and put them into the generated access_token in the IProfileService class?
Right now I have managed to get it working by saving the token using the method "UpdateExternalAuthenticationTokensAsync", which will save the token in the database. Then in the profile service I fetch the token and read the claims into the emitted token.
But this doesn't feel right and while searching for the proper way I´ve seen examples use the class IdentityServerUser that has "AdditionalClaims" property, but I can't find a way to plug that type into the event flow.
Also, when configuring the external IdP you have these "ClaimActions" that can be mapped, but I don't understand what they are.
Finally, I assume that the database tables "IdentityClaims" and "ClientClaims" with corresponding entities should be used for this purpose but I can´t figure out how. Or should they be saved in the "AspNetUserClaims" table to save the actual claim type/values and not only claim mappings?
So basically, there must be a best practice for this scenario that seem to avoid me and I would be greatful if someone could share it.
The main issue in my problem was that the problems I first encountered with persisting the Claims in the AspNetIdentity-Db led me to a wild goose chase.
Returning to this after a week or so made me give this another shot. Turns out that the DI injected "_userManager" wasn't "connected" to the current DI injected "_signInManager". If someone has an explanation for this, please share!
What did work was to use the "_signInManager.UserManager" to update Claims on the user. This properly stores the Claims in the "AspNetUserClaims" table, and can then be retrieved in the profile service.
UPDATE 1:
Of course there was a logical answer to that as well. A user manager is created by default even if you don't call "AddUserManager" on your identity setup during startup. BUT, in my case I have extended the IdentityUser class and now by doing it like this it all works as excpected (where "UserIdentity" is my derived class):
.AddIdentity<TUserIdentity, TUserIdentityRole>(options =>
{
options.User.RequireUniqueEmail = true;
})
.AddEntityFrameworkStores<TIdentityDbContext>()
.AddSignInManager<SignInManager<UserIdentity>>()
.AddUserManager<UserManager<UserIdentity>>()
.AddDefaultTokenProviders();

Microsoft Graph AD Users or people API to search all users?

I'm trying to build functionality into my app for 'admins' to assign users from their AD group to certain groups that are further assigned to app-specific roles. Basically a simple management component.
Adding the user with the oid to a group is easy, the problem I'm facing is finding the actual user.
Currently, the only option I'm seeing is making multiple api requests to v1.0/users (999 items max) and grouping them all in memory and then provide a simple search function to narrow it down.
I have also used the v1.0/me/people endpoint to search for users but this does not reveal all users from the AD group, just relevant users they deal with, so not too useful.
Is there any other api endpoint I could tap into to do a search ONLY on members of the same active directory?
Using the startsWith filter on multiple properties is probably the closest we can get to user search in MS Graph at the moment:
https://graph.microsoft.com/v1.0/users?$filter=startswith(displayName,'sarah') or startswith(givenName,'sarah') or startswith(surname,'sarah') or startswith(mail,'sarah') or startswith(userPrincipalName,'sarah')
Ended up switching to the old AD Graph API and implementing a query on the endpoint as follows:
https://graph.windows.net/{ tenant ID }/users?api-version=1.6&$select=mail,displayName,objectId,givenName,surname&$filter=startswith(givenName,'SEARCH TERM') or startswith(surname,'SEARCH TERM')
If a function receives 1 single param, it will search for that parameter in both givenName and surname but you could configure this to search accross any other supported fields.
You could also completely ditch the $select= completely to get the whole data. I didn't want the clutter though and those keys are enough for me.
Instead of going with startswith You may get better experience using search keyword:
https://learn.microsoft.com/en-us/graph/api/user-list?view=graph-rest-1.0&tabs=http#example-6-use-search-to-get-users-with-display-names-that-contain-the-letters-wa-including-a-count-of-returned-objects

Profile Management with Identity Server

So from what I have read on IdentityServer I should be storing details about the user such as first name and last name inside claims. How would a web application then be able to access the claim information? Since the User Info endpoint requires a valid access token representing the user, I suppose I would need to make an API that could access that returned the profile information of other users? Is this the right way to do it? (use case, web page needs to display contact details that are stored in claims of another user)
Also what would be the way for multiple language profile information be stored and retrieved in the claims? For example a user can have a name/title in multiple languages. I'm thinking of making [LanguageCode]_[ClaimType] (fr_first_name) naming convention and either adding all languages to just the profile IdentityResource or creating separate resources per language.
Your best bet is to set up a project using the IdentityServer4 QuickstartUI example and review that code to better understand how it all works. As of version 4, Identity Server is only focused on the sign-in / sign-out process and the various flows around authentication. They also provide a basic EF-driven persistence model, and they also support the ASP.NET Core Identity persistence model (also EF-driven), but both of those are not meant to be production-ready code.
Basically, persistence of user details is considered your responsibility. That being said, the cookies used for ASP.NET Core authentication greatly restricts how much data you can/should store as claims. The best model is to keep "real" identity provider (IDP) claims as claims, don't add new claims to that list, copy what you need into some other separate user-data table you manage completely, and use the unique claims identifier (almost always "subject id") as the key to your user data. This also makes it easier to migrate a user to another IDP (for example, you'll know user details for "Bob" but he can re-associate his user data away from his Facebook OIDC auth to his Google auth).
Basic persistence isn't too difficult (it's only 12 or 13 SQL statements) but it's a lot more than will fit in a Stackoverflow answer. I blogged about a non-EF approach here -- also not production-ready code (for example, it has ad-hoc SQL to keep things simple), but it should get you started.

What's the simplest way to get user Groups from WAAD?

I've got AngularJS and Web.API WAAD authentication up and running. For client side I use great library ADAL.JS. For backend I use Microsoft.Owin.Security.OAuth. This part went quite smooth.
Now I want to implement authorization based on roles (which will be mapped to WAAD groups). Groups are not included in authentication token so I must ask Azure Graph API for them. I saw various ways to do it, using custom claims providers, adding web services to project, etc. Some examples already providing mapping between groups and roles to use in [Authorize] attribute.
But what is just the simplest example of how to get a list of group ids/names from WAAD providing User ID or username, when I'm already authenticated?
Also, is there any way to get this data in JS to use in Angular frontend, or should I create an API service which Angular should call for roles info?
In the non-JS case, the simplest way of getting groups in the token is by opting in. Download your application’s manifest, locate the “groupMembershipClaims” entry, change its value to “SecurityGroup” or “All”, upload back the manifest.
However note that this won't work for your scenario, because it uses the implicit grant - here the token is returned in an URI fragment, hence a big token would risk blowing past the URL length limits of the browser.
You can always request groups to the Graph and make it available to your frontend via custom action on your API, but from what you wrote you are already familiar with that. Let me discuss the matter here - if there's a simpler route to make this work in SPAs, I'll get back to this thread.
HTH
V.
Update: I verified and in the implicit grant case you will receive groups always via the overage claim. Please refer to https://github.com/AzureADSamples/WebApp-GroupClaims-DotNet/tree/master/WebApp-GroupClaims-DotNet - it will show you how to process the overage claim to retrieve groups. All you need to do is apply the same guidance to a web API instead, and if you need to make the info available to the client expose one or more actions doing so.

Determine whether a user is a developer of a facebook app

I'm looking at ways to secure the admin section of my (cakephp powered) Facebook application. To avoid duplicating functionality, I thought it'd be neat to allow access to people who have been flagged as developers in the app settings.
The question could then be: How do I determine whether a user of my Facebook application is a developer?
Alternatively: How do I obtain an array of developer user IDs for my Facebook app?
I tried looking for your answer myself, and the only thing I found that you could possibly do is to make a group private and invite-only to developers and then use the fb:if-is-group-member tag. http://wiki.developers.facebook.com/index.php/Fb:if-is-group-member
OK, so I found out how to do it by myself. Props to Samuel for giving me the idea.
Basically, the way to do it is to run an FQL query that establishes whether a user is an admin of the applications page (page_admin).
SELECT uid FROM page_admin WHERE uid = 286302657 AND page_id = 31290624157
In the PHP client, this returns an array for developers and an empty string for anyone else.
I decided to use the FQL rather than the API call because it is possible to preload the FQL to reduce calls to the Facebook servers.
Hope this is useful to somebody.

Resources