Background
What is the best way to apply granular right level restriction in ASP.Net core. I've have already set up authentication and my application issues tokens that that expire after a certain amount of time.
My web app also makes use of roles and rights, where a certain role is can be associated with a set of rights. I've seeded the rights and restricted access to them in that even admin users cannot change, create or deleted any (i.e. read-only). The roles on the other hand are dynamic, though the super-admin and admin are fixed. Any user with a super-admin access role has the power to create new roles and assign rights to that role.
What I am trying to do is to restrict access to all the other controllers in my application based on these rights.
I am considering using Policy-based authorization where each right will be associated with a specific policy (i.e [Authorize(Policy = "delete users")]). Then I would embed all the rights the user has in the token I issue out on login.
I am reluctant to implementing it this way since, though the rights may be hard coded, they may/will increase in time, if I have a very large number of rights then I may be a bit inefficient to be embedding all of them into the token.
Is there a better to achieve this level of security???
If you need, in your own words,
granular right level restriction in ASP.Net core
You need to externalize your authorization rather than build it inside your code. The challenge is that existing frameworks (within .NET, Java...) give you roles and at times claims you can use in your code to determine whether a user should have access to a given function / transaction / data set.
But that forces you to write that code (in C# in your case) every time. And, of course, if your use cases change, you need to rewrite your code. it also forces you to create an data model / information model in your database where you create links between users and roles and maybe one day permissions. And then you end up wondering how to handle segregation-of-duty or delegation or other scenarios which neither your code nor your information model allow for.
An alternative is to externalize your authorization to an externalized authorization manager / API that will process authorization requests for you. This is called ABAC (or attribute-based access control; abac). ABAC gives you:
an architecture (see below)
a policy language (xacml or alfa)
a means to query the authorization engine
either via a Yes/No Permit/Deny request/response flow e.g. "Can Alice view item #123?" "Yes, permit"
or via an open-ended interface e.g. "What can Alice view?" "documents in sales"
The Architecture
In ABAC, you choose to build your apps / APIs / solutions in a way that they only focus on the core business logic of the app e.g. serving medical records.
The app itself will not do any decision making as to who can view which medical records. You delegate the decision making to an external authorization engine known as a Policy Decision Point (PDP).
To delegate the authorization, you use an interceptor called a Policy Enforcement Point (PEP). That interceptor can be within your app code or - better yet - sitting in front of well-known interfaces so that it can intercept your transactions / data flows. For instance, if you have an API e.g. /myservice/records then you would have the PEP sit in front of the API intercepting the flow (JSON, XML...)
The PEP sends requests to the PDP e.g.:
Can Alice view medical record #123?
Can Bob edit the SSN field of medical record #34?
Can Carol print record #123?
The PDP replies with Permit, Deny based on policies that use attributes. And this brings us to the second part: policies.
Attributes & Policies
In ABAC (and XACML), you can write any number of policies you like that use any number of attributes you can think of. Attributes are, simply put, key-value pairs e.g.
role=="manager" (yes, role can be an attribute).
dateOfBirth = 1901/04/01
citizenship = "German" and "Canadian"
Attributes can be about users (as above) or resources or actions or even contextual information e.g. time.
record owner, size, classification, department are all attributes of the resource.
Once you've defined your attributes, you can start defining your policies. Assuming the use case is to control access to medical records, you may have authorization requirements e.g.
Doctors can view the medical records of patients they are assigned to.
Other medical staff can view medical records of patients in their unit.
A patient can view their own medical record
A patient can view the medical record of another patient if they are the legal guardian for that patient.
A doctor A can view another doctor (B)'s patients' medical records if B is on vacation and A is on B's delegate list.
No one can view a medical record if they are outside the hospital.
As you can see, you can write any number of policies and you don't need to touch your apps at all. All you need to do is edit your policies.
It gets better: this approach is not specific to ASP.NET. You can use the same approach and architecture for other languages (Kotlin, Java...), layers (API, data, UI...), and so on.
HTH,
David.
Further Reading
Benefits of ABAC
ABAC on Wikipedia
XACML on Wikipedia
I'm also searching for granular right level restriction in ASP.NET Core. Found Casbin library. It supports RBAC and ABAC and PERM instead of XACML. Simple and fast.
Related
I have a C# project called Authentication that allows users to login and get their login credential checked and if passes, returns the token.
I want to reuse that C# Authentication project for other Applications that I am designing. Is it a good practice to store all the users from different Applications in one table or is there a better way to go about coding for One Authentication project for many Applications?
It depends.
There is a difference between code reuse and infrastructure reuse. The former is OK as you get a clean separation between the applications. Sharing a database is not recommended as it can introduce security vulnerabilities if you do not design it carefully.
I would also separate the notion of users and accounts. An account is used to log into an application and load the correct permissions. i.e. the account controls what an user can do in an application while the "user" object describes the user itself.
If you separate it like that, it's much easier to create a reusable library as everything related to authentication/authorization is in its own part. That's because the authentication design rarely changes. What differs in applications is typically the information that describes the user and the kind of customization that every user want to have.
Short answer:
Separate everything related to authentication and authorization into an "Account" object.
Collect everything describing the user into an "User" object.
Reuse the account part, but build the "user" part in every application.
Never, ever share the database between services. It will create a maintenance nightmare.
Every DB should be designed around (and after) the Bounded Context handled by the relative microservice.
In your case this means one DB to store the authentication data, then another DB per-service, with the relative data.
It is perfectly fine to have a Users table in separate DBs holding some duplicate data. As long as you're diligent enough and have a good strategy for keeping that data in sync.
I am using ASP.NET MVC to develop a website for order entry. The orders are not just about buying a product but about building a new customized product given the available product parts.
With MVC is kind of intuitive to restrict permissions to actions. For example, only admins can create new product parts (e.g., call the action CreateNewWheel). Users on the other hand can call the action BindExistingWheelToMyNewCar.
HOWEVER, is there a design pattern to restrict access to content? I need to give permission to content itself that is going to be displayed, not actions that can be executed.
I guess that I can always start creating database relationships here and there based on user roles. But my question is: Is there an existing design pattern that covers this scenario and that I can use as a guide? I want to get as complex as permit, restrict, and inherit permissions that will allow to define which product parts will be presented to end users.
Any hint will be useful.
Thanks,
I want to go one step further than simple roles based authorisation (Admin, User, Super User etc)
and instead do Activity based authorisation .
My thinking was to assign activities to logged in users which related to whether or not they could perform a action.
For example
CreateUser
ReadUser
UpdateUser
DeleteUser
I would create pages that relate to the above activities
i.e
CreateUser.aspx
on each page i would do a check to see if the authenticated user does in fact have rights to access the activity.
i would do this by making use of Roles.
for example
IsInRole("CreateUser")
Previous to this i could assign the Activities (Roles) to the authenticated user after successful login
My only real concern with this is that by doing this when i authenticate the user and build the authentication cookie it will include alot (potentially) of Roles for each user.
for example i currently have 60 activities in my system (but this could increase as we add more features - each feature is in itselve a new activity)
If the authentication cookie has to carry approx 60+ roles (activities) would that cause any known issues?
Can anyone suggest an alternative approach ?
You may want to look into IdentityModel framework. It has the base class for building a custom Authorize module to verify permissions based on Resource-Action pattern. But this is built for .NET 4.5, not sure what your platform is.
.NET 4.5 also includes SessionAuthenticationModule (SAM) for web authentication. SAM can cache the roles between user calls, so that you don't have to send them back and forth in a cookie. Here is some more information on how it works.
Use Operations and Permissions, as described in Ayende's blog. He has lots of articles on the topic.
http://ayende.com/blog/3109/rhino-security-overview-part-i
http://ayende.com/blog/tags/rhino-security
What you want is a capability list approach.
The solution to this is a mapping of roles to capabilities, similar to this:
>Online Anon User Admin
Article ReadOnly ReadWrite ReadWrite
Article.List ReadOnly ReadOnly ReadOnly
Article.Edit Hidden ReadWrite ReadWrite
Article.Delete Hidden ReadOnly ReadWrite
Article.Title.Edit * * ReadWrite
In practice, these will be your coordinates:
>(system state)
The system may be "Online, Offline, Maintenance" and maybe more.
Use the initial > to find the start of your matrix in the file (you'll have many of these). In C# you'll have an enum.
On the same line are the roles:
Anon User Admin
Then on the left side you'll have the capabilities scoped into namespaces and actions:
<item>
<item>.<action>
<item>.<field>.<action>
<item>.<field>.<value>.<action>
The cells will contain one of these values:
Hidden, ReadOnly, ReadWrite or *
The * will mean "inherit" from the parent item or field.
This way you'll be able to fine-tune the permissions based on items, actions, roles and the current system state.
A simple parser translating the list into an in-memory structure will do. Don't put this on a DB, it will be a pain. Keeping it on the text-file/in-memory level is better. Add a FileSystemWatcher to read that file whenever it is changed for additional functionality and leverage lazy loading. Also, store it in Application state memory, not in a session.
Remember: the default will be Hidden (not even read access, the item/action will be completely inaccessible to that role.
Your real concern will then be which roles you'll really need (in my experience a role pretty much maps to an UML actor, maybe with some slight variances), and what the items/fields/values and actions really are. When you write an item you can really mean a group of items. There is no need to map the capability list directly unto a database/entity or code structure. The capability list is on a higher language level, it is semantic and bound to the domain, not to the code (I want to stress this because it's the real power behind this approach).
Once you have implemented this approach with a simple parser and helper object (Information Expert Principle is well advised, avoid Singletons) you'll be able to reuse it in many applications.
I have the following scenario:
Multiple users (< 100)
User accounts in AD (under different groups)
Every group in AD corresponds to a internal department; each department have at least one supervisor
(One may say) We have cross-supervisioning (there are supervisor roles appliable to group of groups, i.e., there may be one supervisor that actually supervises three or for groups - as existent in AD)
Multiple internal systems, half of them web-based, all of them built over .Net framework
Currently we have most of desktop-based systems authenticating users by folder permissions (deployed in network environment using ClickOnce, each deployment folder permissioned by individual users). That does not work for all desktop systems, though; we have two of them using their own embedded authentication system, as follows:
System A consists basically of different datatables (just shows some data in the screen).
All of the datatables are actually different groupings of the same data; this data refers to specific account.
Every account row contain the columns {number, owner, type, data1, data2, data3, data4 ...}; the different groupings are based on number/owner/type.
All of the data(n) columns are numbers (the sum for each grouping is displayed when grouping is done)
For this specific system, the data columns are attributed to groups. So, users in AD Group1 can see columns data(1-5), Group2 can se columns data (7-9) and so on. However, supervisor for each group can see one extra column for their group (supervisor of Group1 can see data(1-5) and data6 - lets call it "special column" for the group); there are supervisors who can see other groups columns (either including the "special column" or not), there are general supervisors who can see all of the columns and there are also users who can see all of the non-special columns. It's a mess.
In order to solve this problem ClickOnce is not enough; so basically what the dev team did was to embed a particular authorization assembly, which queries a database using the current system as a parameter (it supports other systems) and returning a set of column names as results; these results are then used in another query that retrieves only the specific user columns.
This legacy system is about to be replaced by a newer one; after a lot of consideration (including maintainability - the system architecture is a mess), since it's just about data retrieval and displaying with minimal processing we decided to use (some of) the queries and re-write the data retrieval logic.
On top of that, most of the existing web-based systems are hard-code permissioned (if (sADLogin == "userA") {..}); a few of them only rely on ultra-non-intuitive URLs sent to specific users and fingers crossed. Sad.
We'd like to use a more abstract approach for permission (so we can make every system use the same authentication provider). Using web services/WCF just seems appropriate (also considering that I still have to authenticate desktop-based systems and some spreadsheets, maybe using monikers); however I couldn't find an adequate pattern or architecture model for it. There is one WCF Intranet pattern in Microsoft documentation that solves most of it - except that I can't use my Windows Groups as roles. There is an Internet pattern (http://msdn.microsoft.com/en-us/library/ff650091.aspx), however, that seems to handle the roles problem (that's what I'm going with right now), but since it's my first time dealing with WCF security I'd like to have some expert opinions on this matter.
Any ideas?
Thanks,
For web-based applications, this can be simply solved with single-signon to Active Directory using the built-in ASP.NET Provider Model (see: http://msdn.microsoft.com/en-us/library/aa478948.aspx). You can use Active Directory for authentication, and domain groups for authorization. There are several built-in ways you can limit access to pages (using tags in web.config), access to certain parts of a page (using ), and access to code (using User.IsInRole() or RolePermission attribute) - that all works automatically. For web, this is sort of the standard (internet or intranet).
For non-web-based applications, you can actually still use features of that same provider model. You can also pretty easily look up group membership in Active Directory.
If all you need is to know what groups someone is in, this is probably how you should do it. If instead, that database table you have, has something more complicated (like delegation authorization), then yeah - you may want to throw a WCF service in front of that, and have all your applications use that. However, in the case of ASP.NET, I'd STILL use the provider model, and just write my own RoleProvider, so I could still use all the built-in features of the ASP.NET security. Hope that helps.
I'm building a SaaS app and have some issues in dealing with authorization and ASP.NET MVC. I have a previous question and this is kind of taking a cue from comments there. I need to provide somewhat granular security (e.g. lots of permissions) for each user. I realize that any discretionary system can be modeled as a roles system by just creating more roles. But that's a lot more roles than I want to deal with. I don't think roles is going to work for me and would like to work more at the permissions level.
I know the standard response to any question dealing with ASP.NET and authorization is create all your application users as Windows users and implement the ASP.NET Membership Provider. One issue, I'm not going to create Windows users. My question is can the standard ASP.NET MVC AuthorizeAttribute and AuthorizeCore be made to fit with a permissions model?
Also, apparently, the impetus here is really that ASP.NET MVC Caching will break a custom security implementation. Obviously, I don't want my pages to run slowly but I'm not sure I want this caching at all. I'm building a business application; is caching everything really appropriate? It seems that caching would just make concurrency problems much more difficult than they already are. For example, if I am caching all of my customer info pages, including the edit pages, then won't I be defeating any concurrency controls I would have in place (say, timestamp checking)?
If I were you I wouldn't create the users as Windows users, but rather store them in a SQL database. So you now have complete control over how you want to associate your security needs with your users.
Once you do that you can then create a custom security filter by creating a class that implements IAuthorizationFilter. That way you have the control you want to do whatever validation you want, roles based, permissions based, day of the week based, whatever.
You then just attribute your service methods with your new custom security filter, and pass along whatever info you need to ensure that the calling user has the appropriate rights/roles to execute the method.
First of all, you do certainly not need to make application users windows users. the default out of the box MVC has them as users stored in a sql database.
Edit Pages typically should not be cached as they will not really be loaded multiple times with the same data within the cache lifespan. my thought process is that MVC is easy enough to add caching that I would build it out first then performance test to see if it is even a necessary step. (Remember that unless you are looking at large large numbers of client connections then it is typically more economical to make a slightly less performant code and beef up the server hardware.
You do not need to create Windows users to use the ASP.NET Membership provider, it uses SQL tables to store the membership objects. Yes, you can use the Authorize attribute with the membership provider, for example, in a page that only "admins" can edit, you'll use the authorize attribute as follow:
[Authorize(Users = "Admin")]
Also, you don't want to be caching pages where users are going to be editing data, use caching (and you can do it a lot) in areas designated for anonymous users - users with no edit rights.
Hope this helps.