Asp.Net Core Identity - Authorize attribute with roles and caching? - asp.net-core

I have a simple web application in ASP.Net Core with ASP.Net core Identity. I'm using role based authorization on various controllers and it seems to me that the Authorize attribute is not picking up changes to role membership right way.
Let's say I decorate a controller with the authorize attribute and specify a role, like this:
[Authorize(Roles = "TestRole")]
Then I log in as a user which is not in that role. I try to access the controller and the Authorize attribute correctly prevents me to access the controller - gives me an access denied error.
Then I add the user to the TestRole programmatically (I have built a simple user management GUI in the web app where I can manage users and roles). According to the GetRolesAsync() method, the user has successfully been added to the role and everything looks good if I check the records in the Identity tables in the DB. However, I still cannot access the controller - the Authorize attribute does not seem to be aware that the user is now in this role. The role information seems to be cached. If I wait long enough before trying again (a few hours maybe) then this appears to work correctly. If I kill the IIS express process and restart the website, this works immediately, suggesting that the role information is somehow being cached.
I have not been able to find anything which explicitly states that the Role information is indeed cached or how to disable it for that matter. When I change the role membership of users in my system I need the changes to be reflected right away.
Any ideas?

OK - how typical. I've been trying to wrap my head around this for a few days now and as soon as I finally post a question to SO, I find the answer :)
By default, ASP.Net Identity stores user's authorized roles inside
Role Claim after user successful login. Those claims are stored inside
cookie until user logout or close the browser.
Is it possible to cache authorizations in ASP.NET MVC & Identity 2.0?

Related

Add user claims after authentication against IdentityServer 4

I have the following projects:
Identity Server 4, with ASP.NET Identity as a user store for all users of all my apps.
.NET Core 5 Web API
Xamarin app
The flow goes like this:
User logins from the Xamarin app (3) and is authenticated against IdentityServer (1)
User receives an access token from Identity Server, that contains the sub claim
User makes a request to the Web API (2) using the access token
The Web API (2) checks its own database for user permissions
----QUESTION/PROBLEM IS HERE-----
Should the Web API add these user claims (permissions) to the access token, OR should the Web API always check the database for the user permissions on every request made from the client?
Maybe I could add the claims before authenticating with IdentityServer, but this would mean that IdentityServer would have access to the Web API's database. I believe this is not a good practice because of separation of concerns.
Another solution would be to introduce a caching mechanism when the Web API validates the token, so that it doesn't always check the database.
Using claims transformation, it is my understanding that I can add the claims to this 1 request only, meaning that the next time a client makes a request, claims transformation should happen again, since it doesn't return a new access token to the user.
Ideally, I would like the Web API to add the claims to the access token so that the Web API can trust these claims on all subsequent requests. I cannot find a way to do so, though. I've searched for Claims Transformation, IssueJwtAsync (IdentityServerTools), IProfileService, but I think none of these are solutions to this problem.
Is this good architecture? Please do share your opinions on this subject and potential solutions.
Thank you very much!
You need to add these permissions in web api, because users need to access the corresponding resources according to these granted permissions. And permissions are granted when the user logs in for the first time, without the need to access the database in every request.
In this case, you can use Claims Transformation. This link has more detailed steps which can solve this problem.

Angular SPA authentication with Azure AD

Hi I am working on Angular SPA and web API core. I am trying to implement authentication and authorization. I have done as below for now.
Registered one application for my front end application and added required redirect uri and modified manifest file to enable implicit flow. Also assigned some of the roles to it.
Registered one more application for my back end. I added scope in the form api/clientid. Then added client application id which is created in step 1.
User is successfully able to login to application.
Now my JWT token has roles in claim. In my API I have added [Authorize(Roles = "Engineers,Admins")]
So If user has any role Engineers or Admins in the JWT token as claims then they are allowed to access my API's
So far my authorization works fine. But coming to authentication part, currently all users of my azure AD tenant able to do login(User can hit my front end url and add user name and password then It will ask MFA and they will be landed in application home page).
If user is part of any of the roles above then only they can see data in home page because in home page I am calling some of the API's and I have added [Authorize(Roles = "Engineers,Admins")].
If suppose user is not part of above role they are still able to login (login means they are able to add user name and password and MFA) they will be landed in home page but they cannot see any data because api will be accessed only if they are part of Engineers,Admins roles.
My question is If user is not part of Engineers,Admins roles why they are able to login and come to home page. They should be restricted in Login step itself.
I am not really sure I am asking right thing here or I only confused my self between authentication vs authorization.
Currently I am doing authorization based on roles. Same thing I can accomplish using Groups also. In claims I can return groups and create policies and do the authorization. If user is part of the group then I can authorize. I am trying to understand what advantage I will get using roles over the groups.
Currently I have dev, prod and non prod environments. But Azure AD is universal and for there is no environment for azure AD. So Is it a good idea to have separate application registered in azure ad between the environments or can I use same app registered in azure AD between the environments. If I create separate application for each environments what advantage I will get?
I am really trying to understand above concepts and can someone give me some insights on the above things? It will be really helpful to me If someone help me to understand this concepts. Any help would be greatly appreciated. Thank you

How to manage users in ASP.NET core with AD / LDAP? Do I store the users in a database?

I am writing an internal app where all the users are part of AD. I have the following steps to implement this. Is this correct?
Create Action filter to get all HTTP request to website and check in they are in the specific AD role needed (var isUserInRole = User.IsInRole("M2-ITU-PWApplicationDevelopers"))
If user is not in any of the application roles send user to error page
If user is in application role then Add users to SQL DB and link to Role table in DB so now I have the user/role data ready to use in DB along with other data
When user revisits check the database first before LDAP?
How do I set a cookie or something so that every request does not need through process once authenticated ?
Trying to understand the basics.. Maybe I am going about this all wrong ?
Use Windows Authentication. Your application need to be behind IIS to do it in ASP.NET Core 2.2 and lower, but starting ASP.NET Core 3.0 you can do it with Kestrel alone.
If you do that, you can skip steps 3 and 4. When a person is authenticated via Windows Authentication, the application gets a login token that contains all the security groups that the account is a member of. So User.IsInRole is pretty quick. There is no need to store that information in your own database.
You also don't need to worry about cookies.
The added benefit of Windows Authentication is that it can support seamless login: if your site is in the Trusted Sites in Internet Options, then IE and Chrome will automatically send the credentials of the user currently logged into Windows. The user doesn't have to type in their credentials.
Firefox uses its own network.negotiate-auth.delegation-uris setting for the same purpose.

Where to implement the user profile page using IdentityServer4?

I have a solution with 3 projects in ASP.NET Core:
MVC --- no DB (calls the API)
Web API --- MySQL 5.7 own DB
IdentityServer4 + ASP.NET Identity --- MySQL 5.7 own DB
I've managed to get authorization and authentication working between all three apps using in memory clients, users, resources following the great documentation found on https://identityserver4.readthedocs.io/.
Currently I'm using the HybridAndClientCredentials flow which works well with existing users as well as registered users. Newly registered users are saved in IdentityServer DB, using ASP.NET Identity tables.
The problems:
One of my client requirements states that the user should have a profile page inside the MVC app to which the user should be redirected after he is authorized & authenticated successfully.
What I'm doing right now is calling the API in the MVC app, OnTickedReceived event, with the initial claims to create the user in the API DB, but I have doubts that this is the correct implementation.
Since the registration is done and persisted at IdentityServer level and some data about the user is stored there, should I make the profile page there too or should I make a call to the API somewhere in the registration flow to create the user in the API DB too, then redirect the user to the MVC app to input the rest of the details required for a complete profile?
Another requirement states that a user should be able to grant read/write access to another user's details (as in linked accounts or something).
Unfortunately, "it depends".
Let's start by asking "what is the profile page?". What information is on the profile page and is that information specific to your application (MVC/WebApi) or the identity management system.
IdentityServer supports the OIDC UserInfo Endpoint and Profile scope with ASP.NET Identity so that could work well. (http://openid.net/specs/openid-connect-core-1_0.html#UserInfo). You can insert IdentityClaims into the AspNetUserClaims table and get those back when you call the UserInfo endpoint.
But maybe this profile page mentioned in the requirements is information belonging to just the application's domain and therefore has no business being in the identity management system. Then, your current approach is ok- though maybe you could use a Filter Attribute instead of an authentication event (that's just a thought, might not be better).
To me, the decision is about who owns this so-called "profile" information. Is it the identity management system or your business application.
If the profile information can be shared across any client of the identity management system, then put it in the identity management system.

MVC4 - claims based authorization with standard authorization attribute

I have an MVC4 app configured to use Claims Based authentication using the Identity and Access VS extension, which creates system.identityModel and system.identityModel.services section in the web.config.
For authorization I'm using standard attributes e.g.
[Authorize(Roles = "Admin")]
The role should be taken from the Role claim (http://schemas.microsoft.com/ws/2008/06/identity/claims/role) and not from the membership database.
This solution actually worked fine at the beginning. However, when I copied it to other machine I'm getting SQL connection error when the Authorize attribute is hit.
My understanding is that it tries to connect first to the local membership db to check the role. Can I tell MVC to check the role first in the claim?
Since there were no answers I decided to implement my solution as described here:
http://fczaja.blogspot.com/2013/12/claims-based-authorization-in-mvc4.html