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.
There are two problems here.
You are not "adding a new role". You are adding two. The fact that users-created-by-admins and users-created-by-limited-admins must have different sets of privileges means that these are really two different roles. Code it that way. The idea of mapping one physical role over two logical ones based on inheritance unnecessarily complicates things.
You are changing the security model to be finer grained. Where your code previously had three roles, now it has five (regardless of whether the fifth one is officially recognized).
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.
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.
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.
Related
I have a permissions table, which will eventually have up to 100 permissions. Things like "Add User", "Edit User", etc. Would it be acceptable to create a const for each permission in my Permissions model?
The reason is that I'll have a single method that will be used to check if a user has a permission, so I'd want to be able to do something like $this->hasPermission(Permission::USER_ADD) and not have to use magic numbers that would require me to it up every time.
I initially was aiming to trim down the number of records, so instead of having individual CRUD permissions for each resource, I'd just have a permissions for Users along with a corresponding column for the CRUD actions. However, it's not flexible enough for me since there are cases where a particular permission doesn't fall under those CRUD actions. For instance, "View Disabled Users".
I don't particularly see a problem with the constants, but wanted some input if this is a bad practice or the like. Thanks in advance.
I personally don't see a problem with a 100 constants if the domain requires that. What I would probably do in this case is move the constants to the separate class, like:
<?php
abstract class Acl {
const USER_ADD = 'USER_ADD';
...
}
and then check by those: $this->hasPermission(Acl::USER_ADD)
This way your model will not get polluted as you grow the number of permissions.
From personal experience, there is usually no benefit from storing your permission objects in the DB with CRUD as you can add permission objects, but the new feature for it still has to live in the code. Within one of the previous projects, we stored the objects in the code and referenced those in the DB, e.g. vice versa of what you're trying to acheive.
On the other hand, it might be benefitial to check some other (community) solutions for ACL, like the following, for instance:
kodeine/laravel-acl
ACL (Access Control List) Authorization in Laravel 5.1
Lets say i have a number of types of documents in my system. I want to restrict access to them based on three aspects: user roles, ownership and relevance of user to the object. So for example ROLE_DOCUMENTTYPE1READ will grant user a right to read document (other roles such as ROLE_DOCUMENTTYP1WRITE will grant RW rights). Presence of connection to the document (if document has user in his 1:M related_users field) gives user right to add comments to document. And if user is owner of the object he can edit it entirely.
I can easily implement it in controller or even create a trait or something like this, but it would be too ugly and also tedious because there will be lots of entities and actions upon them, not only regular CRUD, but also additional one's that change certain fields. I want to know how usually such things should be done. Maybe there are some architectural patterns that help in this situation? Right now, as i already said, i'm going to check in every action if user is related to entity or if he is even its owner or has said roles.
You can take a look at the JMSSecurityExtraBundle and the Expression-based Authorization Language. They allow to perform complex access decision checks, and because they are compiled down to raw PHP, they are much faster than the built-in voters.
We are currently developing a project management software. And we are having trouble deciding on the correct approach to implement security. We have looked at both ACL and RBAC and are already pretty certain that we need at least a combination of both for specific reasons. But there are a couple of problems that do not have a nice solution in either world. Let me explain:
Let's say you have the following entities:
Users, with different roles, i.e.
Project Lead
Worker
Admin
Projects
Assigned Users
Tasks in Project
Now the following rule should be expressed:
A User with the Role Worker is only allowed to view Tasks, which are related to a project he is assigned to.
This results in that a User is only allowed to view some Tasks in the whole list.
We would use RBAC to give Roles the permission to actually read Tasks. But the condition is not applied as there are specific entities involved. ACL could be used, but we fear the nightmare of keeping the ACL entries consitent with the requirements (Users can change, Roles can change, new Tasks can be introduced an would have to get the correct entries, which is just as complex).
Of course there could be specific queries when viewing a specific project (WHERE project_id = 123), but this does not help for a "View of all my current Tasks", where basically every task can be considered for display, but the ACL would have to be checked for every single entriy.
And how do I ensure things like "Get the first 25 Tasks the current User is allowed to see" without loading all the tasks from the DB and then filtering based on the ACL, i.e. handling pagination.
You need to look beyond ACL and RBAC and consider attribute-based access control (ABAC - see NIST's guide here). Gartner calls this space "externalized authorization management".
With ABAC, you can easily express any rules that take into account not just who the user is but also what the user wants to do, where, when, why, and how. Using attributes to define authorization, you can use XACML to implement policies. XACML is an OASIS standard (just like SAML).
With XACML, you get an API where you can ask questions e.g.: can Alice view this record? But in your case, it's not enough because you want to filter out records from the database. And, as you describe, you want the query to be the right from the start rather than going back and forth to the database until you have the right number of authorized records. This is where XACML becomes particularly interesting because it's technology-neutral. You can apply XACML to Java, C#, and other languages e.g. Python but also apply XACML to different layers (presentation, APIs, and... databases). XACML can be queried in a reverse query way to produce a SQL statement which you could then use to query your backend database for the relevant records:
Which records can Alice view?
Alice can view records in California which yields "SELECT * FROM records WHERE location='CA'"
HTH
Well, I use Yii framework with its nice RBAC layer. I'm not too familiar with ACLs, nor did I need to be, lately.
In Yii RBAC terms, your key to the solution is using 'business rules'.
Bizrules are small snippets of code that are attached to a 'permission' or a 'role' (an 'auth item' in Yii's terms). This code is run dynamically when the need to determine access to a certain 'permission' (lets say, but it could also be attached to a 'role'), and it recieves the 'item in question' (task in your example) and determine actual access to the specific task or not.
Here's a more detailed example:
say you need to have the following permissions:
Edit task (which should be allowed to anyone with the role 'tasks administrator')
Edit own tasks (which should be allowed to the person who submitted this task).
Now, in the 'task edit' code section, you would first check for 'edit task' permission. if ok - allow.
if wasn't allowed, also check for 'edit own task' (using else-if construct). Now on the last mentioned permission there should be attached a bizrule (=php code) that accepts a 'task' object and compares its 'creator id' to the 'currently checked user id'. If equal, it returns true, meaning access should be granted.
That's in a nutshell. If you're interested in more, see this section of the official guide. There are also a bunch of other resources, should you need.
I'm having a difficult time grasping the code behind role-based access control (RBAC). I'm trying to use a "bundle" with the Laravel framework but it only seems to be complicating things more.
What I need for my specific application is three roles. The first and most basic role is just to allow users to be able log into my application, manage their account, and save "favorites" and "deals". The second role I need is to allow store owners to be able to log in and create accounts and deals. The third role is basically an admin role so I can go in and remove unwanted content if need be.
Would there be any anticipated problems with just simply adding an int field to the user table called something like "role"? If a user's role is 0, then they have basic privileges and can't access the admin and owner area of the site; a 1 would indicate the user has an owner role, etc. I would simply check the user's role every time a request was made.
Would this be a reasonable, secure solution, or could I potentially run into problems using this approach?
Using RBAC would give you more flexibility when it comes to managing access to your application's functionality. Each user can be assigned with multiple roles, tasks and operations; each role can consist of multiple tasks and each tasks can consist of multiple operations.
If your application only demands 3 roles, basic, owner and admin, I think it's fine to just add an indicator in your user table. However, if you need to grant certain users access to certain operations, you would need a new number for every operation you want to differentiate access controls. Hence, using that approach would make it difficult to separate permissions based on functionality.
An alternative solution is to use ACL, which I believe it's easier to implement but probably a bit more difficult to manage. You can learn the difference between ACL and RBAC here.
Given a website site has different web pages that can only be accessed by different group of users. Say guest users can only access welcome page/search page, while, administrator users can access pages that update the DB, etc.
I have little experience on this field and would like to adopt some best practice with clean/simple/secure implementation.
If possible, I would like to see some concrete examples/tutorials, even a book resource.
Thank you for your helps
I have found that many applications available online (Wordpress, Joomla, and many other), are very poorly organized in this field (poorer than what I do, in any case).
Take a look at how it's done for MVC frameworks like Zend Framework, CakePHP, Symfony. MVC is mostly used for bigger projects that tend to be much more organized, so I am betting that they have worked a lot on authentication too.
In 2 words, for this to work properly, all your page generation classes (I advise the use of OOP) must be derived from a parent class, which will hold access control methods. Or you could have a class with static functions for access control. Before any action, simply call these functions to check whether the user has access to this functionality. Functionality can be grouped into Classes, with many Methods (in MVC - Controllers and Actions). You can store access information in the database as follows: groupID, Class, Method, Permission, where permission could be a boolean Grant or Deny. To promote speed, extract all user's permissions at first query, store it in an array or object, so as not to generate a query for each permission verification in the user request, but parse the saved data instead..
Each user can have a role or roles in your application / website. Imagine you have an application where some people can edit users and others can insert tasks while others can solve the tasks. Create three roles: user managers, task assigners and task solvers.
Then give users their roles.
Some people call roles groups. You group people to give them permissions. I prefer calling it role because user acts as HR manager or website publisher etc.
This is just a simple example, it's always based on requirements you have. There can be team-based permissions, department-based permissions etc.
http://en.wikipedia.org/wiki/Role-based_access_control
Personally, I have an application broken down to modules. Each module has objects and these objects have actions. Example: user.department.list = in module user, there's an object department and action list (departments). When you create role or group, assign these permissions to that role (group) and users. For role User managers, there're permissions user.user.list, user.user.edit, user.department.list, user.department.edit. After you authenticate a user (to know who's he) load roles he's assigned to. Each page (controller) or each method can check user's permissions - is this user permitted to list departments?