Retrieve db records based on user role - laravel-5.5

I'm new in Laravel that's why I'm pretty sure that my ideas are wrong. To the point...
I'm building Laravel application.
What I have among other:
Users ( build in with Laravel auth with my custom fields )
Roles ( pivot, many to many )
Companies ( each user belongs to company ( many users can belong to one company ).
Locations ( each company has many Locations )
Now I'm in the middle of creating documents. For now it doesn't matter if user_id or company_id will be included in the document header.
What I need is to have ability to e.g.
Show documents - when I go to page with documents list with ADMIN role I will see all docs stored in db BUT when user with USER role goes to the same route ... he'll get the list of owned docs
location/edit/{id} - prevent going to url with not mine id - this is simpler and I guess can be dealed using middleware
I have 3 ideas:
Create somekind of FrontController and inside constructor run method that returns all users_ids ( or all companies_ids ) if user is ADMIN or when USER return only one id. All controller in the application then extends this FrontController
Create Service Class ( end up with many services depends on what model to retrieve ), method to get records from db calling repository with role parameter. Then in this method do the checks which ids should be used.
Maybe User somehow Laravel Policies and before() method. Nów I’m reading documentation but I really don't know how to use it in this case but I feel that this idea is also possible.
I feel that these ideas are "dirty". Can you, please, provide information how to implement this nicely with code snippet? I think this subject is very common and a lot of people will use this thred. I would be grateful for any tips.

One approach could be using local scopes.
https://laravel.com/docs/5.5/eloquent#local-scopes
On your Document model define two scopes:
public function scopeBelongingToUser($query)
{
return $query->where('user_id', auth()->user()->id);
}
// this is the same as doing on your User model
public function documents()
{
$this->hasMany(Document::class);
}
public function scopeBelongingToAdmin($query)
{
if (auth()->user()->roles->contains('admin') {
return $query->select('*');
}
abort(403, 'Unauthorized');
}
Then you can use it later with:
Document::belongingToUser();
Document::belongingToAdmin();

Related

AWS Amplify (AppSync + Cognito) Authorization using dynamic groups per organitzation/tenant

I have an AWS Amplify application that has a structure with multi-organizations:
Organization A -> Content of Organization A
Organization B -> Content of Organization B
Let's say we have the user Alice, Alice belongs to both organizations, however, she has different roles in each one, on organization A Alice is an administrator and has more privileges (i.e: can delete content or modify other's content), while on Organization B she is a regular user.
For this reason I cannot simply set regular groups on Amplify (Cognito), because some users, like Alice, can belong to different groups on different organizations.
One solution that I thought was having a group for each combination of organization and role.
i.e: OrganizationA__ADMIN, OrganizationB__USER, etc
So I could restrict the access on the schema using a group auth directive on the Content model:
{allow: group, groupsField: "group", operations: [update]},
The content would have a group field with a value: OrganizationA__ADMIN
Then I could add the user to the group using the Admin Queries API
However, it doesn't seem to be possible to add a user to a group dynamically, I'd have to manually create each group every time a new organization is created, which pretty much kills my idea.
Any other idea on how I can achieve the result I'm aiming for?
I know that I can add the restriction on code, but this is less safe, and I'd rather to have this constraint on the database layer.
Look into generating additional claims in you pre-token-generation handler
Basically you can create an attribute that includes organization role mapping
e.g.
{
// ...
"custom:orgmapping": "OrgA:User,OrgB:Admin"
}
then transform them in your pre-token-generation handler into "pseudo" groups that don't actually exist in the pool.

Django role based permissions

I'm developing a huge application in django and I need a permission system and I assume that the native user/group permission within django is not sufficient. Here my needs:
The application will be available through multiple departments. In each department there will be nearly the same actions. But maybe an user will be allowed to add a new team member in department A and in department B he is only allowed to view the team list and in the other departments he has no access at all.
I though using a RBAC system would be most appropriate. Roles must also be inheritable, stored in a model an managable through an interface. Any good ideas or suggestions? Regards
What you are looking for is called abac aka Attribute-Based Access Control. It's an evolution of RBAC as an access control model. In RBAC, you define access control in terms of roles, groups, and potentially permissions. You then have to write code within your application to make sense of the roles and groups. This is called identity-centric access control.
In ABAC, there are 2 new elements:
attributes which are a generalization of groups and roles. Attributes are a key-value pair that can describe anyone and anything. For instance, department, member, and action are all attributes.
policies tie attributes together to determine whether access should be granted or denied. Policies are a human-friendly way of expressing authorization. Rather than write custom code in your app, you write a policy that can be centrally managed and reused across apps, databases and APIs.
There are a couple of ABAC languages such as xacml and alfa. Using ALFA, I could write the following policy:
A user will be allowed to add a new team member in department A
In department B he is only allowed to view the team list
In the other departments he has no access at all.
Roles must also be inheritable, stored in a model an managable through an interface.
policyset appAccess{
apply firstApplicable
policy members{
target clause object = "member"
apply firstApplicable
/**
* A user can add a member to a department if they are a manager and if they are assigned to that department.
*/
rule addMember{
target clause role == "manager" and action == "add"
permit
condition user.department == target.department
}
}
}
One of the key benefits of ABAC is that you can develop as many policies as you like, audit them, share them, and not have to touch your application code at all because you end up externalizing authorization.
There are several engines / projects that implement ABAC such as:
AuthZForce (a Java library for XACML authorization)
Axiomatics Policy Server (commercial product - disclaimer: I work there)
AT&T XACML
There are two components to this question:
First, role management. Roles can be achieved through group membership, i.e. departmentA_addMember & departmentB_listMembers. These Groups would have corresponding permissions attached, e.g. "Member | Add" and "Member | View". A department in this context may have more resources included, that require separate permissions. Django allows to extend Objects with custom Permissions.
Second, inheritance. Do I understand you want to have individual Groups being member of other groups? Then this is something Django would require you to implement yourself.
However, should you be looking for a really more complex authentication solution, it may be worthwhile to integrate with 3rd party services through, e.g. django-allauth. There are sure more/other solutions, just to throw in one name.

Check if user has a permission with specific codename in django

I am trying to check if a user has a permission, which I have defined in the class Meta of the model, with a specific codename. At the moment I have:
if request.user.has_perm('app_label.code_name'):
do something
What I am trying to avoid is using the app_label, however using has_perm('code_name') does not seem to work.
The way this function works is that you need to pass the app_label, so not much you can do there.
One workaround can be to write your own wrapper function, something like:
def _has_perm(user, code_name, app_label="app_label"):
return user.has_perm(app_label + "." + code_name)
The reason you need to provide the app label is that permissions are application specific. That means if you have two apps, app_a and app_b, both with a model named Farm, they could both have a permission called can_create_new_chickens. It is very important to understand that there are two separate permissions here:
app_a.farm.can_create_new_chickens
app_b.farm.can_create_new_chickens
These are independent permissions, and a user can have neither, both or one or the other. This means it would be insecure to validate permissions without referring to the application name. Permissions given to a user in one application could affect their permissions in another application.
Back to your question, the answer is no, you cannot check permissions without the application name for the reasons given above.

Rails 4 generic parent model with more specific child models

I am working on my first real Rails 4 app and I have run into a problem with my design.
Currently I have a "Service" model which started out with attributes such as name, online_status, ip, dns_name, port, and service_type. This model has evolved to include many methods and attributes for specific service_types (like auth_tokens, etc.) and thus it is very overgrown. The columns added to the database to accommodate the needs of the different types of services make this model act like a ghetto version of STI without separate classes/models.
The Service model also has methods such as ping() which is used to determine the online_status. I believe the types of services are different enough to warrant their own separate tables because each service seems to have many unique properties and methods.
Example:
A generic service has: name, ip, dns_name, online_status, etc...
A specific service such as Plex will have: name, ip, dns_name, online_status, username, password, auth_token, etc...
The issue, is that I would like to be able to access the more specific types of services from their parent Service class. So when I create a view, I can loop through all the generic services and the more specific services as if they were all the same type of service (or at least be able to access all services in some simple way without looping through each type and appending them).
I also need to access the specific types of models on their own, so doing something like #couchpotatos.each in my view will only go through the instances of the Couchpotato class.
Controllers play into this confusion too since I don't exactly know how to have a single page display all these different types of models from the same controller.
Criticism is welcome! I'm learning, so if this desired design absolutely bonkers, please let me know :D
Ok let's give it shot. I hope I understand your current situation, but the first thing a thought of is using a ServiceConcern containing the shared logic of a service. So a basic example would be:
module Service
extend ActiveSupport::Concern
included do
belongs_to :user
end
def ping
"pong"
end
end
class PlexService < ActiveRecord::Base
include Service
def ping
"plex-pong"
end
end
You would create a new model for each Service implementation that MUST have the stuff a Service should have (in the case above it would be a user_id)
The problem remaining would be a generic way to find all the implementations of the Service concern.
To achieve that, you have to implement a STI, where the Base object would be "Service" with user_id and a type (in the case described above) and implementations with their overrides

Proper way to handle removing a member from a group in REST

I'm designing a REST service which organizes groups and users.
For example:
GET /groups - gets all the groups
GET /groups/1 - gets a specific group
GET /groups/1/users - gets the users in the group
GET /users/1 - the actual user, which may be in multiple groups
POST /groups/1/users - with the post parameters of user_id=1 to add a user to a group
What would be the appropriate way to handle this?
DELETE /groups/1/users/1 seems to be a valid way to do it but then the GET to the same url would return the user record which is a duplicate of the resource /user/1?
or should it be DELETE /groups/1/users?user_id=1?
Wondering which is the most RESTful way to do this.
I think that a good design would make explicit the membership of a user within a particular group - as a separate resource. So, there are groups, users, and the membership of a user within a group.
Therefore, GET /groups/1/users would return a list of membership resource identifiers: /groups/1/users/{member_id} on which you could do a DELETE. Each of these "memberships" is of course associated with a particular user, so you would have to somehow know which member_id is associated with which user_id. The easiest way to do this is to make member_id have the same semantics as user_id, as you suggest in the question (so /groups/1/users/1 means "user 1's membership in group 1"). Following that, if you do a GET on /groups/1/users/{member_id} you could just redirect to /users/{user_id}. Or in a more complex example, this resource would no redirect to a user but link to it and also include some other information, for example the date when the user joined the group, her status in the group, etc.
The other option I can think of would utilize the PATCH method to modify the collection resources (/groups/1/users): see https://www.rfc-editor.org/rfc/rfc5023. But using a DELETE seems more natural.