Laravel multiple user types with groups - php

I am currently building a website with the following user types:
customers
caregivers
partners
agent/mediator
system user (<- special case, I'll talk to you in a moment)
Each user type should only be allowed to do certain things.
However, the system users are somewhat different.
These should be able to be divided into groups, and these groups should also have different rights.
My customer should be able to create/edit these groups including the assignment of given rights. However, it should not be possible to edit the other user types.
I have already seen this ACL packages (https://github.com/spatie/laravel-permission and https://github.com/JosephSilber/bouncer).
But I don't think they support that.
I have also thought of the following approach: There is no user type "system user", but the users are assigned the type of group, and in the code, I check if this type is "customer","caregiver","partner" and "agent". If this is not the case, the user is automatically a system user.
Is there perhaps an open source project that has such a similar approach? I'm currently having a hard time with all the controller classes at the moment (have now merged them into a single user controller and have the $type in the route and a factory class return the right model to me, and then call up a factory again to return the respective service class <- feels totally wrong and badly implemented).

Currently, Joseph Silber is building multi-tenancy for Bouncer. I think that will fit your needs, but it's not released yet for the time I'm writing this.
Also, it's practically 100% sure that you will need to extend a package like that or fork it to adapt to your needs. Looks like a very specific code that will need modifications.

Related

PHP - Class Design Pattern Hellp

I'm writing a timesheet application which would be used by employees and approved/rejected by supervisors. A timesheet has various permissions and only people with certain roles can do certain actions (like for example only a supervisor can approve a timesheet and only if it belongs to an employee under the supervisor's list of employees).
I'm trying to figure out how to structure my list of business objects (models). There are various validations I need to do before I can invoke methods like GetTimesheet or SaveTimesheet or ApproveTimesheet. See the following psuedo-code for an understanding of how my app should work:
GetTimesheetByUserIdAndMonth:
-Validate parameters like UserId, Month-Year value
-Check Permissions:
- If Logged In User is A Supervisor, then see if Timesheet belongs to either this user or to a user under Supervisor's list of Employees
- Else, check if Timesheet belongs to logged in User
SaveTimesheet
-Validate parameters like UserId, Month-Year value
-Check Permissions (same as above)
-Check if user has write ability for timesheet (for example if user had already submitted timesheet before then he can't re-save or re-submit)
SubmitTimesheet
-See if user has a supervisor assigned
ApproveTimesheet, RejectTimesheet
-Logged in User must be a Supervisor, otherwise throw an error
I'm thinking I would need a MyAccount class for the person who is logged in, a User class to represent the person who the timesheet belongs to, a Timesheet class, and maybe some sort of Validation class.
Can someone tell me how best to architect this code and what sort of classes and validation methods I should have? I already have this code working in 100% procedural code...it is very difficult to read and maintain. I'm not looking for full implementation details, just an overall class achitecture/structure. Please give me some ideas and provide me some psuedo-code how to accomplish the above tasks. I can provide more details if necessary.
Thanks in advance.
In your question I can understand 3 different kinds of problems to solve.
The hierarchical structure
Permissions
Validations
A possible pattern to solve this problem is Composite pattern. Some general guidelines to follow can be listed as below.
Use an abstraction which can be used to refer all kinds of users (supervisors, peers etc). Something like 'User'.
Use composite to maintain hierachy.
The abstraction 'User' should have methods like getWritePermission: boolean to provide permissions.
Validations should be decoupled from the core structure. You should maintain those logic using a separate worker class, which will be called at the very higher level of the api call.
I take it you are using an mvc approach. If so you are already on the right track.
Each User action needs a controller. What you already wrote down suits this scheme.
The tricky part is how you store the user:supervisor relation? And is it 1:n or m:n? Anyway I'd go with a User and a Timesheet model (backed by a database) and then go as needed. You don't need to differentiate between user myself and other users on a class object level.
Inside you are your own judge. A Timesheet validator class and a class for checking user rights seem to be needed (additionally to the login system).
Think the following
UploadTimesheetController -> TimesheetValidatorClass -> TimesheetModel -> Database
ViewTimesheetController -> CheckUserHasAccess -> TimesheetModel -> TimesheetView
It's a bit simplistic and not formally correct but I hope you get the idea.

Is there a solution to centralize access control (to entities) based on ownership and other user-document relations

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.

Row level permissions and Laravel app structuring

I'd like to ask other opinions about code structuring of business logic on Laravel applications, mainly regarding permissions at the row level.
For those that don't know it, Laravel is a MVC framework for PHP, much like Rails.
For the sake of understanding, let's suppose a multi-tenant application where each user has his own albums and pictures, so far so good.
Now, each user can invite others to collaborate (by uploading photos) into his album.
Both, the album's owner and collaborator that uploaded the picture may be able to delete or update information about that picture.
Only the owner may edit the album and invite new collaborators.
Collaborators can remove themselves of the album if they want so.
Pinterest should be a nice example of something similar, but our application is probably 3 or 4 times more complex.
The question is: where should I handle that kind of logic?
Laravel proposes the approach of having repositories, entities and services, which I don't fully understand, probably because of the lack of good examples. So the obvious first choice to meet those deadlines was to put it all on controllers (ew!). Now, digging into refactoring, there are many possible ways to un'spaghettize our code:
I've seen people implement ACL at row level (looks kinda dumb and overkill)
It would be possible to turn models into behavior aware objects and not only data containers, something like $album->add_photo($photo) and check permissions at that function
It would also be possible to override model's save method and do there those checks
Or, follow the Laravel proposed road of having separate layers of concern
I suppose that having methods like $album->can_be_edited_by($user) may simplify the displaying of 404 erros on routes not allowed, hiding view's links as well as validating before saving the models
Which would you recommend, and does anyone know any simple, but understandable, example of repositories, entities and services not using .NET?
Thanks!
Edit: I guess that a full ACL system would cause excessive overhead, since there may be thousands of resources associated with each user, but only one role per kind of association. For instance, pictures will have an uploader_id and albums will have an owner_id.
I could be wrong but I think ACLs are OBJECT based permissions (i.e., a user can or can't delete photos in GENERAL). What you want is more custom MODEL based permissions (row level like you said), i.e., a user can delete photos that they themselves created (SPECIFIC ones).
Most Laravel packages are designed for object based permissions I think, but not https://github.com/deefour/authorizer - this one is a great hidden gem. We don't use it in our project but I found that it really covers all the bases we'd need.
We have really advanced model permissions on our app, I have them scattered throughout my models, but I take a very model centric approach, which isn't necessarily very "laravel-esque". In your example with delete, I would override the delete method in your model or listen for the eloquent event and prevent it there. If you have to prevent read/write on certain attributes you could even do that by extending your validator or using custom mutators/getters, serializers or listening on events. More on where to add business logic in my question/answer here: https://stackoverflow.com/a/27804817/796437
I'm still trying to find the best approach, if I do I'll update this - but thought I'd post.
In Laravel you can use Policies or use solutions, like Symfony Voters.
For Laravel exists same package - Laravel Simple Voters.
Using this, you can check access to custom objects, looks like this:
Access::isGranted('edit', $post) // current user can edit this post?
You can put this logic, to example, into middleware, if you wish check requests to controllers.

Complex Righty System: ACL, RBAC and more what?

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.

PHP - Good practice to apply multi-level PHP User Authorization

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?

Categories