Reputation: 23
I have a web application with very simple role based access control. The current setup has three roles:
-SUPER ADMIN
-ADMIN
-USER
Each page request checks the users role against the minimum access level for that page and grants (or denies) access to that page based on the result of the comparison.
There is also a one to many relationship between ADMINS and USERS; Each admin is responsible for one or more users.
I'm now faced with the challenge of adding another role (LIMITED ADMIN) and restricting each USER'S access based on whether the admin responsible for them has the role ADMIN or LIMITED ADMIN.
Is there an established best practice for a situation like this? It would be simple enough to modify my current access logic to handle this scenario, but as the application grows I'm starting to wonder if I should move to a more robust access control model. Access control lists are the first thing that came to mind, but they do not seem to handle the case where one user's access can be limited by the role of another.
Upvotes: 2
Views: 824
Reputation: 31832
There are two problems here.
Access control lists provide a level of indirection between your code and a given role. Rather than checking the user's role, you merely validate the requested action - Create? Read? Update? Delete? Yes or no, simple decision. The code never changes. Instead, the UI that assigns roles packages up the sets of privileges when creating the ACL. In the user-creation screen the permissions the administrator sees are defined by the level of that admin - Limited, Regular or Super. But once the ACL is set the question of whether it was set by an admin or limited admin is irrelevant. At run time it's simply Create? Read? Update? Delete? Yes or no, simple decision.
Once you have done this then adding a new role is as simple as packaging up the right collection of privileges on the ACL. Adding a new privilege is easy, you just extend the ACL. And none of these changes affect how previous code interprets the ACL.
Remember, privileges are tangible things that control access to real resources. Roles are abstract concepts represented by collections of privileges. Once these two things are separated in the code, changes like those you describe will be MUCH easier. The only place the two meet is in the UI where users are created and privileges assigned.
Upvotes: 1
Reputation: 16208
Be explicit. Rather than having to check the user's associated admin every single time they access a resource, a simpler and more maintainable approach would be to implement this as a distinct user role. For example, when a user is created by LIMITED ADMIN, their role could be LIMITED USER.
(Of course the same effect can be achieved with access control lists, too. The same principle applies -- assign an explicit role to the user, not an implicit access level based on the admin responsible for them).
A consequence of this is, you also need to be explicit about what happens to the user's role when their admin is changed, admin account is disabled, etc. But I would argue that even with the original implicit approach, you still have to consider these situations -- indeed, any boundary cases you overlook are more likely to result in security holes, whereas explicit roles are inherently safer.
Upvotes: 1
Reputation: 1905
You are asking the wrong questions, instead of asking 'what role is the user' you should be asking 'can the current user do x'. This turns spaghetti code into a very flexible role based access control.
Bad code:
if ($user === 'Admin' || $user === 'Super Admin' || $user === 'SubAdmin'){
// spaghetti
}
Good code:
$resources = array(
'edit_page',
'view_page',
'delete_page',
);
$roles = array(
'admin' => array(
'edit_page',
'view_page',
),
'superadmin' => array(
'edit_page',
'view_page',
'delete_page',
),
'user' => array(
'view_page'
),
);
function can_do($x){
$user_role; // (currently logged in user role)
return in_array($x, $roles[$user_role]);
}
There is a subtle but very important difference. Now we can ask, "can the current user do x"
if (can_do('view_page'))
{
// clean code
}
Now we only need to ask if we can do something adding a new role (superduperadmin) is easy and you only need to make changes in one place.
Upvotes: 1