Where and how to "cache" ASP.NET role data

Design choice

Assume two ASP.NET MVC authorization scenarios / roles. Both are designed to minimize impacts on the medium or data warehouse:

  • After extracting the "MyRoleProvider" information from the database, it is subsequently stored in the AuthTicket user data, which, in turn, means that the auth-cookie contains information about the role. In addition, in this story, the storage and retrieval of this role information is performed by a separate implementation, completely outside of "MyRoleProvider".

Or...

  • After extracting the "MyRoleProvider" information from the database, it is subsequently stored in the session and accessed from there. More precisely, the "MyRoleProvider" class will itself access (and update) internally.

Again, both of the above stories are aimed at minimizing the latency of getting to an external store using caching information. Both work fine. The question is, are both design options the same? If not, why?

Problem

It seems that not a single "best practice" is indicated anywhere that says: "Your (custom) RoleProvider should always know where the role information is, whether in the session, cache, database, etc."

Also, there seems to be no (solid) manual anywhere that explains what things you shouldn't store in " userData " in authCookie. In which small documentation and manual there are only two things:

  • 'userData' can store additional user information (undefined, wide expression). I saw only one example of code on the Internet that included storing additional third-party identity / authentication information.
  • Do not put too much data in 'userData', because this may cause the cookie to become too large to be migrated (some browsers limit the size of the cookie).

What is it. From the above guide, no one says bluntly: "It is best to limit user data to authentication information only." And I, of course, did not see the document that said: "It is a bad idea to put authorization or the info role in userData, because ..."

Derive best practice?

My own answer is that both design options are equal - no. I want to present my arguments and find out from you if:

  • Do you agree.
  • You do not agree, because I am making useless vanity.
  • You do not agree; although my argument is true, there are even better arguments in favor of why my thinking is ultimately untrue.

We hope that the concept of best practice will appear in response. Now for my argument (s) ...

My argument (s)

I believe that the second design story should be taken because it represents the best modularity: role information is completely processed inside "MyRoleProvider". The first option is uselessly mixing authentication (extracting identity from a cookie) and authentication issues. Indeed, all ASP.NET built-in security mechanisms share these two themes; ASP.NET core functionality never stores role information in authcookie. If someone wants to confirm this, try reflecting these classes: FormsAuthenticationModule, FormsAuthentication, IPrincipal with RolePrincipal implementation and IIdentity with FormsIdentity implementation.

ASP.NET RolePrincipal deserves special attention. This allows the role information to be actually stored in the cookie, but this is the second cookie separate from the auth-cookie. In addition, this strange idiom still requires consultation with RoleProvider. See the Example section of this MSDN documentation .

Next, explore RolePrincipal, look at RolePrincipal.IsInRole (). Although any such IPrincipal-based class combines identity and role information programmatically, the internal implementation still supports RoleProvider as the only source of role information (note the link to Roles.RoleProviders... ):

  public bool IsInRole(string role) { if (this._Identity != null) { if (!this._Identity.IsAuthenticated || role == null) { return false; } else { role = role.Trim(); if (!this.IsRoleListCached) { this._Roles.Clear(); string[] rolesForUser = Roles.Providers[this._ProviderName].GetRolesForUser(this.Identity.Name); string[] strArrays = rolesForUser; for (int i = 0; i < (int)strArrays.Length; i++) { string str = strArrays[i]; if (this._Roles[str] == null) { this._Roles.Add(str, string.Empty); } } this._IsRoleListCached = true; this._CachedListChanged = true; } return this._Roles[role] != null; } } else { throw new ProviderException(SR.GetString("Role_Principal_not_fully_constructed")); } } 

This kind of ASP.NET β€œone-time” deep assumption about where role information is found is why the role role should be combined in RoleProvider. In short, I affirm:

  • If you store role information in a cookie, the reason ASP.NET does not have the built-in ability to combine it into an auth cookie is because ASP.NET strongly divides the problems between the various providers.
  • Any RoleProvider needs to know where role information can be found, whether in a cookie, session, or otherwise.

Output:

Do not put the-info role in the auth-cookie and make sure that your (custom) RoleProvider knows all the places where the role information is found, whether it is a database, web service, session, cache or cookie.

I agree? Do not agree? Thoughts?

+4
source share
2 answers

It seems to me that you are asking an absurd question. No one in their right mind will store role data in an authentication cookie. ASP.NET does not do this precisely because they provide a RolePrincipal that will store it in an encrypted separate cookie.

The whole problem in the cookie makes no sense, as this is a part of the RolePrincipal implementation. An application does not need to know where role data is stored.

So, my question is for you ... Why are we even discussing this? You ask whether it is better to do something contrary to how the system does this, and then argue why you should not do this in a way that no one will ever use.

In addition, your cookie comment about RoleProvider incorrect. RoleProvider does not create a RolePrincipal , it is done inside the frame. The choice of whether to use cookies is not in RoleProvider , but rather is provided by the RoleManagerModule environment RoleManagerModule , and the IPrincipal method is created by the framework.

The example in RolePrincipal has nothing to do with RoleProvider . In fact, the RoleManagerModule controls this functionality. RoleManagerModule is an HttpModule that is installed in IIS and runs as part of a pipeline. He doesn't even know about RoleProvider , and basically that means Roles are filled from the cookie at a very low level, and when `RoleProvider gets close to launch, if it finds pre-existing roles, it just does nothing.

+3
source

There are many different problems and design options that determine where to actually cache information, be it a cookie, session, or some other provider.

Of course, the first question is whether to cache it at all. We are sure that there are problems with constant access to the database to obtain fairly static information. However, there are equal problems with the fact that you can immediately block someone.

Only if an immediate response is not needed, caching becomes viable. Because of this, there can be no best practice regarding caching authorization .. and, of course, there are no best practices on where to cache it if your application does not need this level of security.

Assuming this is not a problem, there are trade-offs with location.

Cookie
If you put it in a cookie, it can be captured and subsequently replayed. It also slightly increases your Internet traffic, because a cookie is sent for each request.

Session
If you put it in a session, you will either limit yourself to a single web server, or you must have session state stored in a location accessible to the entire web farm. If you take the last route, then it is likely that you are storing the session in the database somewhere, thereby completely destroying the reason for its beginning in the session.

Memcache or other
It is like saving roles in a session; however, it is usually stored in memory on a separate server and is usually fast. The disadvantage is that for a balanced load on a web farm, this can add another point of failure ... if it is not grouped correctly. At this point, you increased the costs of developing, deploying and maintaining the project ....


Ultimately, there is no best practice. Only a bunch of compromises that are highly dependent on the situation. Honestly, for this data type, I will not cache it at all. Usually it is relatively small, and queries for it are usually pretty quick. I could think about it if we spoke to tens of thousands of users, but at this level there are many other operational considerations that will ultimately make the choice obvious.

+7
source

Source: https://habr.com/ru/post/1440633/


All Articles