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.
Related
I'm creating a Symfony2 website that has users and each user can have multiple permissions like this:
User1: manage users , manage sales , manage repository
User2: manage repository
user3: manage sales , manage repository
...
for such a system what is the correct permission system to use?
Roles or ACLs or voters or something else?
Thanks
Roles
Roles are OK if you want to grant "general" permissions.
For example, if you need user to be able to manage all or users, then you can create a role for it, for example ROLE_USER_MANAGER. Or if you want to grant him rights to manage sales, you can grant him ROLE_SALES_MANAGER role.
So basically, use Roles when you have limited number of permissions to some entities generally.
You can use them for other stuff by granting roles that contain entity names and ids for example, ROLE_MANAGER_REPOSITORY_23 and then using custom voters you can know that users with that role can manage repository with id 23. Even though this approach can work, I personally don't like it.
ACL
If you have a lot of dynamic permission granting, especially towards individual models, then ACL is the way to go. It is usually a bit less performant, as it needs to fetch more data from the data store, but is a lot more suitable for this purpose.
With Symfony2 ACL, it's incredibly easy to grant and check permissions, and even to allow individual users to grant permissions to each other.
Furthermore, introduction part of Symfony ACL docs shows you both of these approaches and also point out some ups/downs for each.
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.
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.
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?
That's kinda vague so here's the meaty stuff:
I have seen authentication systems that do one of the following
have a separate role table for each roles, and a separate permissions table, all users in one table
have a separate table for administrators
there's a lot that I have missed, I know. But what I'm trying to really ask is:
How should I design my database in a website that I have a lot of kinds of users and each with different access?
How will I make it so that my script is flexible enough if I decide to add another type of user with another type of permissions?
I currently have a User class and am planning to make my Administrator class which extends that User class. Or is that a bit of an overkill when I can have them all in a single class and just assign necessary permissions?
you can have tables -
user (user_id, name ...)
permission (perm_id, name, desc)
role (role_id, title)
user_role (user_id, role_id)
user_permission (user_id, perm_id)
role_permission (role_id, perm_id)
This way you can have as many roles in the system as you require, and you have both role level permissions, user level permissions.
you can add an additional level of abstraction. basically you add a table in your database to manage user groups, and assign group permissions to those groups. different users can have multiple groups.
this way you can quickly change permissions to a predefined set of rules, without needing to change every user separately. you can also change the permissions for a group of users at once
I think you need to think about several concepts here. The first would be an access control list (ACL) and then second would be authentication.
In an ACL, you define resources, which are objects that you want to restrict access to and roles, which are objects that may request access to a resource.
The way I implement my ACL, is using Zend_Acl. I have a table called user_roles
user_roles('user_role_id', 'name', 'permissions', 'parent_role_id')`
I also have a table called user_role_maps that maps a user's ID to a user role ID. (You could just have this as a column on the user table, but that just depends on how you feel about normalisation ;-) .) I can then construct my Zend_Acl object from this table and then, when a user is authenticated, I can determine which resources they have permission to and what actions they can perform on a resource. (A resource implements Zend_Acl_Resource_Interface so it is identifiable by Zend_Acl as a resource.
As for authentication, this is a simpler concept (in my opinion), you've probably already figured out some form of token matching authentication system yourself. The crucial aspect is using the authenticated user's ID to determine their role. The Zend Framework also provides a package for this in Zend_Auth.
I've used a lot of Zend Framework recommendations here, the reason for this is that their packages have very few dependencies on other packages, making it quite simple to plug components in. I'm sure other frameworks provide ACL packages that you could use, or roll out your own if you have the time and understanding.
Good Luck.