Coding, is? Fun!

Saturday, July 04, 2009

Roles and Permissions - Authorization models

This post tries to capture the two different models in place for authorization in web applications.
Usually every web app has at least two different roles of users accessing the application. If you take a business application, like a timesheet managemenet system (my favorite example), you have employees who access the system to enter their time and task details. You have supervisors who access the system to approve such timesheets, and also enter their own task details.
The problem of identifying who the user is (by means of passwords or certificates) is the domain of Authentication. But, once the user is logged in, we have to allow or deny the user their various actions - this is the domain of Authorization. Authorization efforts are usually distributed all around the application code.
In the above timesheet example, an employee who is NOT a supervisor should not be shown task details of other users. This is accomplished in code by not showing the list of other users to a non-supervisor.
So, at some point in the code we have to make a decision of showing a link or not based on the user's authority.
If the application has to be really secure, the authorization will extend horizontally and vertically.
Horizontally, in another area of the code, let us say that the supervisor sees the timesheet of a person reporting to him/her. The "Approve" button for the timesheet is in that screen. The code that displays this button should still check if the user has the authority to approve or not. That is, even though a non-supervisor will NEVER gain entry to view another user's timesheet, the code for approval should still assume that they can and disable the approve button at that point.
Vertically, when the operation to approve a timesheet is actually called, the code should again check for the current user's authority to approve timesheets. That is, disabling buttons and links on the UI alone is NOT sufficient for authorization.

Thus, we can see that the code has to check for authority at different points in a given user's context. There are two different models for managing such authorizations.

Role and Permission based Authorization

For simplicity, let us consider a case of disabling or enabling the "Approve" button for an user. Remember the example extends both horizontally and vertically.
Authorizing a user based on their role assumes the following narrative:
A user who is in a supervisor role is accessing the Approval screen. Should the "Approve" button be enabled or disabled?

Authorizing a user based on Permissions assumes the following narrative:
A user who has the Approve permission for the Timesheet object is accessing the Approval screen. Should the "Approve" button be disabled or enabled?

Readers familiar with .NET would see that the first method corresponds to the Principal.IsInRole() method in the IPrincipal interface. There is no equivalent for permission based authorization in .NET.
One of the most important challenges in implementing these models is that they should be configurable or data-driven. That is, an user's roles should be available in the database. Similarly user permissions should be available in the database, in the case of permission-based authorization.
Let us consider these models in more detail below.

Role-based Authorization

The Users of a non-trivial web-based system will be available in the database. During initial design, the roles throughout the system will be clear - in the Timesheet system above, there are supervisors, non-supervisors and system admins. System admins are a hidden role in most systems.
So, we need a Role table to store the system-wide roles along with their identifiers. The Role table is usually small and only has a few rows.
Next we need a table mapping Users to Roles. This is usually a link table, say, User_Role_lnk.
Note that users in this model have multiple roles. This is usual in most systems - Roles are not mutually exclusive. In the Timesheet example, a supervisor also needs to access regular features like entering timesheets for him/herself.
Thus, typically a User has multiple Roles.
When the user has been authenticated, the system loads their roles in some object and makes it available in the current thread's context. So at different points in the code, developers can check for role authority this way:
if(currentUser.IsInRole("supervisor"))
{
enable approve button
}
else
{
disable approve button
}


This is a simple model, but it can get complicated some times. Since the user can belong to multiple roles, for some code, you may need to do this:
if(currentUser.IsInRole("supervisor") or currentUser.IsInRole("admin")
{
do something
}

In a system with many overlapping roles, you could easily have many such if..else conditions, thereby creating code that is difficult to understand or maintain.

Permission-based Authorization

The argument for authorization based on permissions is as follows:
At every point when you need to check authority, we are concentrating on what role an user belongs to INSTEAD of concentrating on what the code itself needs permissions for. If we flip the foreground and the background, then we should focus on what permissions a block of code needs.
The ideal, in the case of Permission-based authorization, is code that looks like the following:
if(user.hasPermission("Approve") on object Timesheet)
{
enable Approve button
}

This generally creates more maintainable code. But the details of the data model can be complicated.
Remember that we need more entities to define permissions. Let us look at them, in light of the pseudocode above.
We need a User entity as before.
We need a list of Permissions
We need a list of Objects
Note that the goal is to be data-driven. Usually we call the objects that we are "protecting" (such as the Timesheet object in the above code) as a Resource. In one implementation I saw, the Resource name along with its fully qualified namespace was used to represent the protected Resource in a "Resources" table.
So, unlike the Role-based model, we actually need a list of Resources in the code that we are protecting.
At first, this seems difficult to understand. In case of disabling the "Approve" button, what is our Resource name? What Resource in the database should it translate to?
The "Approve" button protects the Approve operation (which is probably setting a flag) on the Timesheet object, which is an instance of the Timesheet class. So, the Resource we are "protecting" or "seeking authority for" is the fully qualified name of the Timesheet class.

So till now, the table model consists of Resources, Permissions and Users.

Roles in a Permission-based system

But when we are actually assigning permissions, we still would like to assign it to a group of users than a single user. The User inherits those permissions simply because they are a member of a group.
Sounds like a Role, doesn't it?
So, the permission based model needs to include the idea of roles for ADMINISTRATION, but when the Permissions are being evaluated at Runtime, the roles work only in the background. The developer still checks only for permissions. The roles are usually not exposed in the Security API.
Let me explain with an example:
We have a user A who is associated with two groups, G1 and G2. G1 has the Approve permission for the Timesheet object. G2 has the Create permission for the Timesheet object. Therefore, user A gets the Create AND Approve permissions at runtime.
This can of course quickly lead to another scenario - if G1 has Approve permission for the Timesheet object and G2 explicitly has the Deny permission for the Timesheet object, what does the user get?
This problem is not unlike the problem faced by an operating system when you login to Windows in an Active Directory network. Of all the conflicting permissions from different groups you belong to, which one wins?
This is a detail of implementation - it is upto the business analysts to determine if Deny trumps all permissions or not. You just have to be aware of this possibility when implementing a permission based system.


Implementation of a Permission-based Authority

As a summary, a permission based system requires a custom implementation. It requires you to take into account group conflicts. It also requires you to enumerate (in the database) Resources that you are protecting.
Building a GUI administration system for Permissions is complex, compared with simply populating User-Role link tables.
But this model is very common in business applications and produces more maintainable code.

Labels: ,

1 Comments:

  • Use of annotation or attribute based permission implementation results in much cleaner code. I recently worked on a Java project where we used annotations for persistence. It might have resulted in less efficient execution, but the development was a lot faster with fewer issues. I'm sure the same holds good in .NET.

    By Blogger Sridhar, at 1:45 AM  

Post a Comment

<< Home