I have an ASPNET CORE 2.0 website that is published to a web server farm. I am using Identity Role/User claims for authorization. I have a large number of claims associated with the logged in user, which is bloating the size of the application cookie. I see a few techniques for dealing with this situation, but am unsure what path to take.
Using a custom ClaimsTransformer: create a custom DB store outside of the Identity Role/User claims tables and load the claims on TransformAsync. I'm not sure if there is a better solution that doesn't involve a DB call every round trip to the server.
Specify a Distributed Cache Session Store when specifying the ApplicationCookie. I'm not sure if this will resolve the bloated cookie issue.
Using a sticky Session to store user claims. I don't think that this works with claims authorization ([Authorize])
How do I use Claims Based Identity across multiple web servers when the user has a large number of claims?
Cookie size is basically the strongest argument against "everything as a claim," and it's unfortunate because that model works pretty well, otherwise (I've been in your shoes). Just as you suspect, the best approach is to restrict your claims to the bare minimum and use the identity (subject id) to retrieve more detailed app-specific information from a database as needed.
If database response-time is a concern, you're basically back to stateful session data. Microsoft would likely guide you towards Redis in-memory caching. Not sure if that's an option on Amazon, I use Azure.
I tried the ClaimsTransformer routine, but it became a larger hassle constantly addressing "is this really a claim or just something we're treating as a claim?" versus just separating persistence/retrieval of real IDP claims versus internal application-level user data.
Related
I wanted to try this code/solution to my ASP.net (VScode 1.69.1) but I am not sure where is the "Global.asax". Anyone know how I can apply the code below to asp.net core?
https://teknohippy.net/2008/08/21/stopping-aspnet-concurrent-logins/
I would not advise you to use that code, it wasn't even good advice back in 2015, but we can explore the concept and it's flaws which might help you come to a better overall solution.
This post will provide some context to the issue: Single Instance Login Implementation but is not a direct duplicate. The original source article does actually go into better detail about the general issues with this approach: http://www.nullskull.com/articles/20030418.asp
Using an In-Memory cache is not a viable option for production as multiple instances of the application would not share the same cache, especially if the application is hosted across multiple servers or serverless infrastructure that is configured to scale out beyond a single instance.
If all you want to do is block new logins, if the user is already logged in, then a server-based or cache concept itself is the right solution, conceptually to enforce a single instance across different browser sessions and across multiple servers will require that there is a server-side cache or store that holds the source of truth for all active connections. This could be in the form of a database or a distributed cache like REDIS.
But this is not a practical model for how users actually use their browsers and devices. Instead of blocking new logins, it is more practical from a user point of view to expire or force close the existing logins. The problem with only blocking new logins is that if the user doesn't have access to the original browser session that holds the login, then there is no way to log out the previous session, you would have to wait for it to timeout. The challenge with being able to expire a login session is that your clients and the server code must be designed to round-trip to the session store to validate the session token. Most default JWT or even cookie implementations do not do this, they will rely on the expiry or validity information in the token itself, and bypass consulting the store.
Instead of the article you have found, please try these resources:
ASP.NET Core security topics
Can I force a logout or expiration of a JWT token?
JSON Web Tokens (JWT) are Dangerous for User Sessions—Here’s a Solution
I'm currently trying to set up a session management interface for users to essentially log out their sessions that may be active on other devices. However, I'm still somewhat new to Asp.Net Core 2.1 and am having trouble finding good documentation on the subject.
I thought about using the distributed SQL server cache system. However, after further inspection, I found that the keys for the distributed cache are not equal, as they shouldn't be, with the session id.
I also tried writing some middleware that stores the session id in a separate table with a many-to-one relationship with the user table. This table would have a sliding expiration dates and a tokens. If the session had a token, the session would be persisted.. My thought was to assign a token to the client using a cookie. That way if their session expired, it would lookup the session with the cookie token and, if one existed, log the corresponding user in. Then it would copy over the token and delete the old session. Kind of like a 'remember me' system. If the token is null and the session time was expired, it would be disposed of. If no session was found, or the user field is null, it would log the user out. If duplicate tokens were found, it would log all of the sessions with the corresponding token out. However, I'd rather use some kind of built in feature, if it exists, to minimize the risk in opening up unwanted security vulnerabilities.
I've also found examples where you can log another user out... But, because Asp.Net Identity is cookie-based, it allows the user to continue to use the site until their cookie expires... This would be undesirable in this scenario.
I know that Asp.Net had the IHttpSessionState, but I've been unable to find a similar interface in Core. Unfortunately, most solutions I've found either point to implementing a custom-made system, or they just show how to log the current session out.
Basically, is there already some kind of mechanism in Asp.Net Core that already implements something like this? If not, is there any specific interfaces that I should be researching and trying to implement? If not, should I resort to writing my own system? If so, are there any holes in my logic above?
Here's an example of what I'm talking about, pulled from Facebook's account management. I know that it's a much larger scope website, but I wouldn't think that such a feature would be extremely hard to integrate? Might be wrong though...
(Redacted some personal info)
We need to make a central auth server for multiple applications that we build, while still having roles and claims which are specific to that particular application. Let me explain with an analogy using various services by Microsoft.
I sign up for a Microsoft account and hence my authentication info is stored in a central server. Now i login using the account and assume a fresh start i land up at account.microsoft.com, now i go to msdn click on sign in, it takes me to the login page on auth server then to the consent screen and back to msdn logged in, now i go to xbox and does the same thing. Now MDSN and XBOX are two completely different applications with each having it's own Api, web apps and mobile apps, but using the same auth server.
Till now i have been making independent applications using Identity Framework, and am reasonably comfortable with it, but this is comparatively much more complex than what i have done till now. I was looking through IdentityServer4 to have a central auth server and has completed all the tutorials present on the official doc site, so i have a basic idea of the concepts.
What i need is to have each application be able to specify it's own set of roles and claims without even having any kind of knowledge about other applications, and also the central server will be having external authentications enabled, hence ASP.NET Core Identity in central server.
Current Architecture
Central Identity Server (using IdentityServer4, ASP.NET Core Identity, Entity Framework)
One Central DB for Central Server
Multiple Applications Sets (API, MVC App, Xamarin Mobile Apps)
One or more DB for each application as per need
Things i am able to achieve till now
Customize an identity resource to get user claims stored in db but if i add one roles, it returns me the role repeatedly the number of times as the count of API resources and Clients
Alternate solutions that i came up in my mind
Store the claims and roles in application specific DB, but i guess that i will be facing these issues
too much effort wiring up the auth logic, as it will have to first get the identity from central server and then get claims from the application specific DB
not sure how i can do it using asp.net identity on client side
unused table on central auth server
duplication of auth logic across applications
These stack overflow questions gets the most closest but are not the exact solution
ASP.NET Core Identity and Identity Server 4 - [Roles, Claims and
IdentityResources]
IdentityServer, Claims and Roles
How to add additional claims to be included in the access_token using ASP.Net Identity with IdentityServer4
Any guidance that takes me in the right direction will help
EDIT #1 : It seems like someone has flagged this questions as off-topic, so just want to clarify that i am looking for a specific code/solution using identity server 4 and asp.net core identity and not some recommendation, though any guidance apart from the answer is welcome for better clarifications and understanding, but just the code would suffice, and i feel that it's as per the guidelines of the community.
EDIT #2
I tried doing authorization on client side as suggested by #travis.js but i am unable to understand how do i implement the claims on client side something like [Authorize(Roles="Admin")]
I think your alternative solution is the "right" one.
Addressing your concerns:
too much effort wiring up the auth logic, as it will have to first get
the identity from central server and then get claims from the
application specific DB
Sounds like exactly the right amount of effort to me. The Central Server does authentication and each app does its own authorization.
not sure how i can do it using asp.net identity on client side
You don't really need ASP.NET Identity on the client/app side. Identity is handled by your central server.
unused table on central auth server
Non-issue. But you could still use that table for its intended purpose just at a more macro level.
duplication of auth logic across applications
This does not sound like a duplication of logic. The Central Server does identity/authentication and each app is responsible for determining its own authorization logic.
I am using a stateless design for a MVC5 Web API 2, ASP.NET application.
User roles are created by administrators by selecting permissions.
Each user in the application is assigned a custom user role, one role may be shared amongst users.
Razor views are structured based on the permission in the users role.
MVC and API controllers are available depending on the permissions in the users role.
For each request to the server, the users permissions need to be processed.
I can think of 2 ways to do this:
Store the id of the users role in the Role claim and perform a database lookup to retrieve the permissions for each page-load/request.
At the user login, retrieve all the permissions assigned to the users role, serialise them as JSON and store them in the Authentication claim. Then at each page-load/request, de-serialise the JSON back into objects and process the permissions.
Which of these would be the better option?
Option 1 is a lot slower than option 2.
Is there a security risk of storing the permissions in the cookie?
Is there a better or alternative solution which is quick and secure.
Storing permissions and other sensible data inside a cookie is always a very bad idea as it's quite easy to manipulate them. Trusting cookies requires an additional server-side check which defeats the purpose of storing it inside a cookie.
You're way better off only trusting the data that is under your control, aka the data in your database(s).
Depending on your application it might be useful to lazily evaluate permissions only when you really need to access them if the performance hit is too big. Keep in mind that you can make use of things like Redis to improve performance dramatically.
So again, depending on your application I'd probably go for option 1 as it's the more secure way.
I'm re-writing a website from the ground up for azure. Each user has ownership of a number of objects, and has a number of permissions. Together, these determine what they are authorized to do. The question is, how should this information be stored. I want to do the authentication myself, using custom logic.
For performance reasons, I'd like to cache these authorization lists for each user once they're logged in. Can someone give me a sample for how to store & access this session information securely and efficiently.
Edit
I looked into the App Fabric Access Control, but that seemed overkill as I was going to have to create a separate site for authentication, which doesn't seem to make sense. Would the claims based authentication make sense separately though? How would you do that if it does?
Would it make more sense to just keep the username in a cookie in the traditional way and then re-query table storage with each request to get the permissions etc.? How would storing the username work in Azure?
Cost is a big factor here as it's a very small site (by azure standards) but I want high performance for a small number of users.
If you want to run with a reasonable amount of availability you need to run your site with two instances. If you're running with two instances you need to use a session provider that's no the default InProc one. Your choices are:
AppFabric Caching (which you don't want to use because it's too expensive, fair enough)
Azure Storage Session Provider. Don't use this. It's an interesting experiment, but it's only sample code, it's slow and doesn't cope well in production.
SQL Server session provider.
If the permissions for a user weren't going to change while they were logged in, you could just store their permissions in session. This will probably be fast enough. However this information will need to be read from SQL for each request that uses session and it is overhead.
If you wanted to make things faster you could just store the user ID in session and load the permissions into a static dictionary (keyed on user ID) when needed. These items will need to be expired after a certain amount of time or lack of use.
Well, you could use the Azure App Fabric cache to store the session info. ASP.Net can be configured to use it as the backing store for its session state as like a normal custom session state provider.
This article from MSDN shows you how to configure it:
http://msdn.microsoft.com/en-us/library/windowsazure/gg278339.aspx
From your code you just use the normal ASP.Net way to get/set the state.
Be aware though - it could be expensive ($45/month for 128MB of cache).