I have to create an Authentication and Authorization environment for my ASP.NET CORE MVC Identity 2.1 application, with an API backend and IdentityServer4 as Authorization Server).
I have administrators
I have Projects.
Every user has to be in at least one project, except administrators.
I would give users a claim like "Role" and store something like "admin"/"user" in it.
Now it gets more complicated.
In every project, users have different roles, and sub roles and once again sub-roles of sub-roles (so, three tiers).
Currently, I solved the problem by using action filters and write them in front of each controller/method (where I see them fit). I also created tables for these three tiers, so that I can store which user is in which tier (and of course they have different access rights depending on that).
I also want the user to be able to have multiple projects open at the same time (in different browser tabs) so that they can switch between these as they desire. I currently solved this by sending the project id on every request in the URI.
I thought about using claims instead of my current action filter solution. I read a lot into that and watched the Microsoft Virtual Academy videos regarding this topic. But I fail to understand how I could use that in this scenario. Should I do claim requirements and copy the code from my action filters in them because claims identity can't handle my case by default?
Am I doing this completely wrong?
Related
SITUATION
I have a database where I have usernames and their linked permissions and code that works with it. Think of it as blackbox that gives me user's permissions as an Enumerable of enum values when I supply username. I need to use it.
I also have an ASP.NET Core 3.1 MVC web application that needs to use Windows authentication and Custom Authorization based on those permissions.
I want to store those permissions for a minute (or ten) because the network is unreliable and querying for user's permissions every time takes a long time and they don't change that frequently. I can't do anything about the speed, I have to work with it.
I have an AuthorizeAttribute implementations where I specify a list of permissions (enum values) that user needs to have to get to the action in a controller.
To be more specific I have an older .net framework asp.net MVC application where I go around this problem by having my own custom principal with my list of permissions and saving this principal in a cookie.
I'm slowly learning asp.net core and when I started reading about authorization and authentication in it, it was enough to make my head spin from information overload.
SUMMARY
I have a list of user's permissions that I need to store for some time and don't know what to do make my own custom authorization happen.
I what I currently have is probably not going to work for me in ASP.NET core MVC application and can't find viable option before getting overloaded by the myriad of options available.
What I need is a push in right direction written in simple language (for an idiot) in a direction to look into to make my requirements work.
CURRENT (NOT IDEAL) SOLUTION IN ASP.NET FRAMEWORK MVC
Example of what currently somehow works in .net framework asp.net mvc, but is probably far from ideal:
in global.asax override WindowsAuthentication_onAuthenticate, where I check if there is a cookie with the user's data and the user is authenticated.
If the user is authenticated but there is no cookie, create a principal (containing the user's permissions) and serialize and encryt it to FormsAuthenticationTicket to the cookie.
in Application_PostAuthenticateRequest get data from the encrypted cookie and set it up in the HttpContext.Current.User as the principal.
The authorize attribute is then just going to take the array of specified permissions and check in HttpContext.Current.User if the user has them.
Can someone recommend me how to narrow my search for a viable solution (or a viable solution)?
The requirements
we have 3 modules ui, api, IdentityServer (IS) (client, resource, IS in terms of IdentityServer)
all the modules should be separated from each other (separate dbs for IS and api)
api is stateless (all the needed auth info got from tokens)
the api will have resources like \projects, \users, etc.
another entry point may be added in the future like another-ui which will communicate with the IS and api and will have its own claims
The problems
The main problem is that the resources of api like \projects\12345, \users\, \projects\123456\users, etc. may also be needed as claims in IS. For example, api module reads the access token of authorized user and see the claim projects that equals ["222", "12345"], so the resource \projects\12345 or \projects\123456\users are allowed for that user.
Users are identities in IS and resources in api at the same time. Projects are claims in IS and resources in api at the same time.
I thought of book-keeping these entities that are represented in both modules through the ids (guids). But ids won`t solve all the problems.
Some of them are:
creation of a new project with its id should grant that user the rights to use it in the future, so we need save the claim for that user in some way. The modules are separated, so should we call the IS api to create that claim for that user and then proceed with project creation. How the communication between the two (IS and api) should be organized? Do we need to register the api as another client in IS?
How should updates of users in IS like changing the email, phone (the values one may log in with) will update the api. I thought of showing warnings that the auth email (got from token) does not match the info email.
Could you, please, explain how modern systems coupe with the per resource access?
Thank you for your time.
First you need to make sure what a claim is.
Claim is not a permission or a role, it's what the user is. Based on what the user is, then you can assume the permissions.
https://learn.microsoft.com/en-us/aspnet/core/security/authorization/claims?view=aspnetcore-3.0
A claim is a name value pair that represents what the subject is, not what the subject can do.
So starting from that, you can get the claims and do the following.
Let's say that a user is the owner of a project. When the new project is created, the project api can update the identity server and add a claim to the user saying he is the owner.
In your apis the owner of a project has a set of permissions and based in those, access to specific resources
In the DDD Domain driven design world, a little bit of data duplication does not matter. So duplicating the possible claims that your application needs in terms of roles (again, not ids but a mapping of one or more claims to specific roles) is not a bad practice.
When you update some kind of claim from your api, you should do so in a transactional way. Think first if you need the email to be saved in both. You will get the user data from the claims anyway on every request. Is it even something you need as a claim? If not have it in your api only.
Communication between apis is organized in many ways. If you need transactions or eventual consistency is something you should also consider. Communicating with events or queues is the microservices way to go, with patterns like the SAGA being the coordinator.
situation is as follows:
I have an existing MVC 5 application and created some very, very basic log-in functionality for it. I just have a table for users and passwords in my database, and use forms authentication to check if a user exists (and some actions can only be done if you are logged in).
Now I would like to extend the authentication system to use roles. From what I gather, I need to make a table in the database with roles, and of course give users a field that contains their role.
But I don't know how I could then use that information in my MVC application for authentication (using that nice [Authorize(Roles="admin")] syntax). All the examples i found for using the identity system use the template site, which I did not use to create this app (I started from an empty project).
From my understand i think you can Use the User.IsInRole() method or AuthorizeAttribute to verify the user in a particular role instead of Membership method or identity method.
We are developing a non-public business application and will be using ASP.ENT 5 with Identity 2.x! The app will be accessed by employees, managers, both via intranet and internet.
The big caveat is that we do not want to use AD or Azure AD, as our customers probably do not have that. We also don't need individual logins such as facebook or twitter.
We need to hook the ASP.NET Identity mechanism up to a legacy database, which has its own entities for roles, users, and permissions.
For starters, there is a tree of "resources" that can be assigned. E.g. a resource would be "Add new product", "Remove product", "Edit product". You can assign a group of users (=role) to one or more such resources.
My question is how do you hook such a custom scheme up to Identity 2.x?
There is also not one "admin" role, but many roles on different levels of access that depend on the job/position of the user. A manager (="admin") would create those roles and assign users.
Is there a way to prevent ASP.NET from creating the default dbo.AspNetUsers, etc. tables and instead use the legacy tables?
Is it possible to do split up
1. Authentication -> handled by Identity 2 + ASP.NET
2. Authorization -> handled by custom code, e.g. a account controller
Does anyone know of resources on this topic?
There is that possibility ofcourse. What you are looking for is a way to have the identity 2 mechanics but use your own mapping.
You can look at this question for answers: ASP.NET Identity User and Roles in Multisite and the following video shows you some info about using existing Db's with identity 2: https://www.youtube.com/watch?v=elfqejow5hM
I did something similar but for multitenancy purposes. The concept i used was explained in an earlier question i did: Middleware for multisite ASP.NET Identity 2
To be precise, there is no out of the box system that you can use, but Identity 2 is very customizable. In order for you to have your own tables, you have to create a custom DbContext or override the IdentityDbContext. That is the starting point, where the tables being used by the Identity 2 are set.
Hope this helps!
We have a multi-tenant ASP.NET application. So far tenants have been isolated from each other, however now we have Agencies that manage multiple tenants and want to be able to manage all their tenants with a single user account. I'm trying to figure out the best way to accomplish that, hopefully without much change to the existing technologies that we are using.
Relevant technical details:
AspNetSqlMembershipProvider for both membership and roles
C# 4.0 (soon to be 4.5)
Forms Authentication
Both aspx and MVC (v3) pages
Assume 100 or more tenants, so any solution needs to support that
I believe the requirements are very similar to the security model for SQL Server. We have one set of logins which represent all the users that can login to the system. Users should be able to be given roles to one or more databases (tenants). Example: User Bob has admin role in company A, but only user role in company B. We also have a "sysadmin" role for my company's employees which allow us access to any tenant as well as specialized administrative privileges such as create/delete tenants, etc.
I've done a lot of research into various libraries, frameworks, etc, and I haven't found any convincing evidence that some other library or framework will be better than what we currently have. So I'm currently thinking of just figuring out how to make Sql Membership provider do what I want, unless someone can point me in a better direction. I'm also not sure I know the best terms to search for in this.
I've got 2 options I'm considering:
Add only a handful of roles to the membership provider and handle all the questions of "does the current user have this role in this tenant" outside of membership provider. Membership provider would be used to handle basic access to the system.
Add tenant specific roles to membership provider. We would have (# of roles) x (# of tenants) total roles in the system. Each new tenant would add another set of roles to the system, e.g. "Tenant A:Admin", "Tenant A:User", etc. Would need some additional tables to manage the relations as well as probably some custom code to ensure that access is requesting the correct tenant-specific role from the membership provider.
Are either of these options good? Or should I be looking elsewhere for support for this?
I don't think you are going to be able to shoehorn multitenancy into any out of the box role provider, so you might as well keep using SqlMembershipProvider (and SqlRoleProvider). Even the newest Microsoft.AspNet.Identity still assumes a vanilla many-to-many between users and roles. What you really need is to add a 3rd column to the primary key of that many-to-many table, which will id your tenant, i.e.:
user: 6
role: 4
tenant: 17
user: 6
role: 9
tenant: 18 (and so on)
...with this, you are able to have users with different privileges for different tenancies, all using the same set of role names.
If you went with option #2, then your [Authorize] attributes would explode. Imagine this:
[Authorize(Roles = "TenantA:Admin", "TenantB:Admin", ...)]
public ActionResult Post(int id, SomeViewModel model) {}
... all of those attributes would have to be written at compile time unless you went with a custom AuthorizeAttribute, which you could do. But even then you are left creating a new set of roles each time you add a tenant to the system, which should not be necessary.
I work on a big multi-tenancy application. We came to the conclusion that it was easier to maintain separate databases per tenant, and have the web application automatically switch database contexts, rather than try and use an over-complicated database schema to model different tenants.
The benefits
Tenant data is compartmentalized by default into different databases
Tenant data can be exported as a database dump for client MI
Database design is vastly simplified
The drawbacks
You have to manage multiple databases - operations challenge
You have to develop database switching code
Implementation using multiple databases
We used a configuration database that has client settings based on an account code. That account code can come from a login screen or you can map subdomain to client code.
When the app starts you load all tenants into cache (containing connection strings)
On every request you have to determine the client and then switch the db context
I have also developed a multi-tenant application that uses a single database. You quite quickly have problems making sure that you don't cross tenant data. Every query needs to include a tenant id filter. The database queries are therefore always slower as a result, although you can index everything you can to try and improve the situation.
With regards to the Membership question, you can install the membership schema into each tenant database.
What doesn't work
The ideal alternative would be to dynamically switch the ApplicationName, but although it seems to work, ApplicationName is not thread safe, therefore this would not be reliable:
Because a single default membership provider instance is used for all
of the requests served by an HttpApplication object, you can have
multiple requests executing concurrently and attempting to set the
ApplicationName property value. The ApplicationName property is not
thread safe for multiple writes, and changing the ApplicationName
property value can result in unexpected behavior for multiple users of
an application. We recommend that you avoid writing code that allows
users to set the ApplicationName property, unless you must. An example
of an application where setting the ApplicationName property may be
required is an administrative application that manages membership data
for multiple applications. Such an application should be a single-user
application and not a Web application.
Alternative: MembershipReboot
Multi-tenancy is hard in .Net. An open source alternative to using the built in Membership is to use MembershipReboot, written by Brock Allen. It has some excellent features including multi-tenant support out-of-the-box:
single- or multi-tenant account management
flexible account storage design (relational/SQL or object/NoSql), samples using both EF and RavenDB
claims-aware user identities
support for account registration, email verification, password reset, etc.
account lockout for multiple failed login attempts (password guessing)
extensible templating for email notifications
customizable username, password and email validation
notification system for account activity and updates (e.g. for auditing)
account linking with external identity providers (enterprise or social)
supports certificate based authentication
proper password storage (via PBKDF2)
configurable iterations
defaults to OWASP recommendations for iterations (e.g. 64K in year 2012)
two factor authentication support via mobile phone SMS messages or client certificates
The most common use case will be to integrate this into an ASP.NET or
ASP.NET MVC application, though the library can also be used over a
network as a service.
Alternative: ServiceStack REST
Another alternative if you are building modern web applications that heavily use JavaScript MVC frameworks such as AngularJS, EmberJS or BackboneJS is to use ServiceStack REST services. ServiceStack has a long list of Authentication features, and from my experience of SS, I find it has an extremely well thought out API model.