I am using Azure B2C to take care of user management in my ASP.NET Core application following this example.
My application needs to store custom data for each user. This is something I haven't seen done in any Azure AD examples.
The stored data is too complex to be stored in AD user attributes.
What is the best practice for implementing this user ownership scheme when using Azure AD?
Would adding userID property on all my models make sense? This ID would then be the ID of the owning user in AD. Is there a better way?
I present two possible approaches possible but I recommend the first one:
Store user's data in the external data store and correlate this data with the user using objectID (user ID) from the Azure AD B2C. In this case, once the user is authenticated, in the ID Token returned to your application you will find the ID of the user. Then you can query data using this ID value. This approach is recommended when you have complex model and large amount of data related to user is stored.
Get user's attributes from the external data store during user authentication (calling web API, and using objectID (user ID) from the Azure AD B2C) and embed them in the ID Token that is returned to your application. Please note that this approach is sufficient when you do not have large portion of user's data, that has to be embed in the token. You should not use it when you know that there will be huge amount of data returned because you will end up with large tokens or reach size limitations of HTTP headers. The one more downside of this approach is the fact that user's data is retrieved only during user authentication so if some property will be updated in the data store, you will have stale data in the ID Token.
Here I created the video how to retrieve the data during authentication but the concept is the same - you store user data in the external data store and refer to it using objectID (user ID from the Azure AD B2C):
https://youtu.be/_umcCiSOFv0
Related
I'd like to ask for advice or direction to any article/documentation on how to add custom claims to user identity. Project I am working on is using Azure B2C with Microsoft.Identity.Web.
I am searching for a robust way of adding a custom claim during web request in an web app. The claim would contain permissions obtained from an application database. So I also need a way to store that claim between requests, so I don't trip to database on every request.
The model of roles and permissions stored in the database is quite complex and dynamic (managed by admins), thus simple storing custom claim in B2C via graph API is an option.
I was thinking about stepping in with a middleware doing claims transformation:
Is this ok with Microsoft.Identity.Web or is it something that I shouldn't do?
Still not sure how to persist the claim between requests - is there any robust way while using Microsoft.Identity.Web?
If you want to have permissions in the token, and I presume that would be the optimal way, then I'd go with saving those in the user object as a Base64 encoded JSON for example. You can have quite complex structure which AAD B2C would just return in the token for the user. Then you may do what you want with this value in once it hits your API. It's in the token so it's properly signed and you get the token with every request so you don't think about reaching to any database.
A user should be able to register, submit their own data to be stored in mongoDB and when they use the API endpoints such as "/data", they only get the data they created as opposed to the data created by every user.
I understand authentication up to level 5 security and only studying OAuth now.
Ideas I have in designing this is maybe finding a way to have the endpoints require and the username and any created data store the username.
So /usernamedata gives the person their data and that way, other people's data stays safe? Cause I don't imagine a user would somehow be capable of hacking into my DB and with restrictive endpoints they'd only have access to their own data.
I'd love some feedback on my strategy!
I'm using User.FindFirstValue(ClaimTypes.NameIdentifier) to retrieve the user Id of the current logged in user. The resulting seems to be a random string.
If I look up a user in Azure AD the ID there looks like a guid. And if lookup a user in the Graph Api the Id is also a Guid. Is there some way to relate the two properties?
Or is the .net core current user not related to the logged in Azure Ad user?
I plan to use IdentityServer 4 on ASP.NET Core with ASP.NET Identity as the data store. This is the first time I use a central authentication/authorization and I am wondering how to solve the following question:
Assume I have users with claims like name, role etc. and a Web API (scope) that allows these users access to measured values from hardware devices. IdentityServer will allow me to authenticate known users but now I need an access control that knows which users may access which device data.
Where do I store this information? Since it is specific to the scope I guess it should not be stored in the IdentityServers store. On the other hand, if I store it in the scopes own database I somehow need to connect it to the users defined in the IdentityServers store. Should I define user IDs that are unique to all scopes and IdentityServer?
You will need to correlate the User Ids that IdentiyServer returns with users defined in the scope's database.
I believe that there is a User table and a UserLogin table where you could track the different logins for each of your users.
Then, in the scope's database, you can then specify which users have access to what device data.
This is a bad idea and will probably lead you down a road that you should not.
This means that your client application requesting the scopes will need to know which user has access to which scopes even before requesting a token from your IDP (otherwise your token request will not work). Rather model these as user claims. Then on your WebApi you can do normal claim based authorization.
What is the best practice in azure mobile services to use different authentication providers (Facebook, Google, Windows e.t.c.) and understand that this three logins belong to the same user.
Out of the box if a user1 choose to use Facebook for authentication on his mobile phone and add some information to the app, and later he (user1) try to login with Google on his tablet, he will not see his information. Because they are two different users with different tokens. And I want to take some additional information from authentication providers (email) and has my own user table which contains email and other profile info shared for user no matter what provider he uses. How could I achieve it?
P.S. I use .NET as a backend and Windows Phone as a client
There isn't an out-of-the-box solution here. You would probably be best served by using a lookup table which maps a static user ID that you define to different identity provider IDs. Then, everywhere that you take a dependency on the user ID, you would do a lookup to match the current user identity to your static identifier. Your user ID is what gets stored everywhere else in the database.
The important detail here is that a Mobile Services token maps to a single provider identity. If you look at the user ID, it is actually provider:providerID. So we need to obtain two tokens and validate both together in order to associate two IDs.
On the client, you would have to manually prompt the user to link accounts. You would stash the current token in memory during this process, log in with the new provider, then call and API on the backend which does the association.
string existingToken = App.MobileService.CurrentUser.MobileServiceAuthenticationToken;
App.MobileService.Logout(); // allows login with new provider
await App.MobileService.LoginAsync("google");
await App.MobileService.InvokeApiAsync("associateToken", existingToken);
On the server, you need to be able to validate existingToken (the new one being implicitly validated by restricting the API to AuthorizationLevel.User)
Within that API, you can validate the token using:
IServiceTokenHandler handler = this.Request.GetConfiguration().DependencyResolver.GetServiceTokenHandler()
ClaimsPrincipal claimsPrincipal;
bool didValidate = handler.TryValidateLoginToken(existingToken, ConfigurationManager.AppSettings["MS_MasterKey"], claimsPrincipal);
You should probably also look up the user ID in your lookup table to avoid conflicts.
So overall that's a rough sketch of a possible solution. Unfortunately there isn't anything more turnkey.