Introduction

In the context of this paper, activity is defined as an action that a web application exposes and its users can execute. According to this definition, in ASP.NET Mvc, each public action method can be thought of as a distinct activity.
Activity based authorization, which is also known as permission based authorization, proposes that every activity that an application exposes must have a corresponding permission code (unique) for that action. Further, there must be a permission set associated with every authenticated user of the application. This permission set is nothing but a list of permission codes that identifies all the activities the associated user can carry out.

Don't use roles in ASP.NET for authorization checks

When it comes to authorization – validating whether a user is allowed to perform a specific action – You often see that the default inbuilt approach in ASP.NET is to do a role check. “Are you admin? Sorry, but this action is for administrators only! Access denied!”
You must be wondering what’s wrong with this way of putting authorization checks. After all, the privilege level of a user determines the kind of actions he can perform, isn’t it? Absolutely! But if you hardwire privilege level (roles) with actions, you are at a significant disadvantage.

Lost Flexibility. If you want to re-adjust permissions for role(s), you have to modify the source code. If you want to introduce new roles, again you have to modify the code.

Lost Visibility. As your application grows, the number of actions (thus permissions) also grows proportionally. You might choose to document which role has what permissions from the very beginning. But documentation has no direct and real time link with the actual system in place and primarily for this reason, over time, it suffers from inaccuracies and incompleteness. Hence, you can never be 100 percent confident that the document you have exactly represents what permissions belong to a given role in the deployed system.

Lost Control. As you lose ability to change permissions for roles as and when you want and when you don’t have direct and accurate visibility into the most important aspect of the system, you lose control of the system. Malicious users may gain access to sensitive parts of the system just because developer mistakenly marked an admin-only action with guest role (maybe he was in a hurry to test some related change – and then forgot to remove the role check again because of the deadline pressure). It is possible that you may never get to know this (since the change was done for some immediate purpose so no point of documenting it) or even if you got lucky and you somehow find it, it can still cause serious damage by the time you make the change and re-deploy the system. Also, taking system offline at peak time may freak out your customers and may leave a bad impression causing irreparable damage to your business.

The solution? Do activity-based authorization checks

If you carefully observe you would realize that roles are actually a higher-level abstraction. A role is a way to group a set of activities to permit users possessing that role to carry out all those activities. In this, activity is at the lower level in the abstraction hierarchy and by design, the lower layers shall never have knowledge about the higher layer. By associating role with the action method, you are actually breaking this important software design rule.

"So what is the right way to do it?" Glad you asked! The right way is to do the inverse of what you are doing; that is, associate activities with roles and not the other way round.

How to do activity-based authorization checks in ASP.NET

First, remove role checks from your code, completely. Instead, put an activity check for each action. For doing this,

Consider that each action requires a unique permission code that user must possess to execute the action.

It is easy to build this unique permission code: for each action, you have at least two data points at your disposal – action name and the entity which this action is related with. In database parlance, actions on a given entity are summed up as CRUD. So for example, if a blog post is an entity, typical actions on a blog post are create, read, update (edit) or delete. So you can create permission code for each of these actions as follows:‘CreatePost’, ‘ReadPost’, ‘UpdatePost’ and ‘DeletePost’.

Now you have permission codes, you need to store it in the database. Why? Because only then you can associate these with the roles.

Note, you can actually live without roles in this approach – you would use roles as a grouping construct, so as to be able to quickly assign the same set of permissions to multiple users.ASP Security Kit gives you the ultimate flexibility of choosing either of the approaches by introducing a new concept called Implied Permissions.

You would also make a provision to associate these permission codes with users through another table in the database either by directly associating permission codes with users, or by creating another intermediate roles table, associating permission codes with it, and finally associating roles with users.

Whichever way you choose, you will always load the permission codes, and not the roles, in the application for authorization and each action method must validate whether or not its permission code exists into the loaded permissions for the current user.

You might ask “what if I forgot to add a permission code to the database or if I added it, but incorrectly (spelling mistake)?” Well, no problem, in that case the system would deny users to perform that action and that is better than accidently letting user perform sensitive/privileged actions which they aren’t entitled to. Also, you would definitely very soon get to know such a case and it is very easy to rectify that without a need to touch the code and impacting the live system.

Implied permissions instead of roles – more flexibility and complete control

Remember, while learning how to do activity-based authorization checks you had to make a design choice – either directly assign permission codes to users or, first associate permission codes with roles and then assign roles to users. However, with ASP Security Kit you aren’t restricted with this limitation. This is because ASP Security Kit introduces a new concept called implied permissions. In this design, you don’t have roles as a separate construct. Rather, you have permissions aggregating other permissions. For example, in a real-world scenario, if a user has a right to delete an entity record, he should also be able to edit it. Similarly, if he can edit it, he can also read it. SO you see, there’s a hierarchy in actions – existence of an action implies other less-privileged actions, and that’s the essence of implied permissions.

With ASP Security Kit, you dynamically define what permissions implied by a given permission, and by doing so, you just need to assign the higher-level permissions to users and all the implied permissions are loaded recursively. So, for example, you can create‘Admin’ permission and make every other permission implied by it. As you can see, this eliminates a need for separate role construct while at the same time, gives you more flexibility that is difficult, if not impossible, to achieve if you had roles as a separate construct.

Infering permission automatically: don't repeat yourself (DRY)

In how to do activity-based authorization checks section above we learnt that to build a unique permission code we can use entity type name and action name.
Often we create separate controller for each entity in our domain models and name that controller accordingly. Based on this assumption, ASP Security Kit can automatically infer permission code. This means you don't have to type the permission code and clutter your code with more attributes. Of course, you can completely override this behavior, for a controller, for action(s) or for both.

Instance/resource awareness is a must in real web applications

Note – Inbuilt role based authorization in ASP.NET has no concept of instance awareness.

Any authorization system is not complete in and of itself until you could make it independently work on entity instances (records). Let’s go back to our example of an entity blog post. Suppose you want to assign permissions to users to perform CRUD operations on blog posts. In a real-world scenario, you’d need to do something like this:

Assign user(s) a right to create a new post.

When a user creates a post, he should get rights to update/delete it but not all the users in the system should get those rights. (leave moderators/admins as of now.)

So now you need a way to associate permission codes not just with an action, but only if that action is being performed for a specific entity instance.ASP Security Kit has strong inbuilt support for instance awareness. If you use ASP Security Kit, you can create two kinds of permission codes:

General – Permissions that aren’t related to an entity instance. ‘Create’ permission is one of the most common examples that comes to mind. You don’t create a record that already exists.

Instance – Actions that are related to an entity record or instance. ‘Read’, ‘Update’, ‘Delete’ ETC are examples of it. You need a record to exist before you can apply these actions on it.

ASP Security Kit gives you this feature built upon existing implied permissions feature. You got it right! If you permit a user to delete an entity instance, he is also authorized to perform less privileged, implied activities (like edit/read) on that same entity instance! Since you specify implied permissions for a given permission, both of these features (implied permissions and instance awareness) together give you the ultimate flexibility of managing who can do what, down to individual entity records.

Conclusion

ASP.NET provides you with basic inbuilt role-based authorization system which is good enough to create simple, small and personal websites. However, SaaS, productivity or line of business (LOB) based web applications demand much more granular control on user activities than inbuilt role-based authorization could offer. Web applications run in a dynamic business environment and must be flexible to accommodate frequently changing organization structures and needs.

Activity-based authorization gives this flexibility by deferring the need to create roles until run time and doesn’t require you to modify your source code just because you need to change role/permission structure. Managing permissions is the job of administrators and not of the developers and activity-based authorization insures that this holds in reality.

Instance awareness is absolutely essential in a multiuser environment in order to make sure that users can only access and modify data that belong to them. It shouldn’t be an afterthought; rather it must be inbuilt with activity-based authorization infrastructure to insure granularity and security.

Get ASP Security Kit

ASP Security Kit is a complete solution to do activity-based, instance-aware checks for your ASP.NET Mvc applications. Additionally it has many other useful related features that give you complete control of authentication and authorization for your ASP.NET web application that you would never want to turn back to the old way of doing things.