beatswitch / lock Goto Github PK
View Code? Open in Web Editor NEWA flexible, driver based Acl package for PHP 5.4+
License: MIT License
A flexible, driver based Acl package for PHP 5.4+
License: MIT License
Hi guys,
I'm trying to write a Phalcon driver for Lock, but testing it with the PersistentDriverTestCase you've provided, I get 10 failures. Since Phalcon's ORM isn't much different from Laravel's Eloquent, to which you've kindly provided a driver, I felt it should be a pretty easy job converting that driver to Phalcon, but I'm at a loss now.
Maybe these failures give you a clue what I've done wrong or where to look for the problems? The failures are as follows:
it_can_check_multiple_permissions_at_once
PersistentDriverTestCase.php:230
it_can_clear_multiple_permissions_at_once
PersistentDriverTestCase.php:242
it_only_clears_the_requested_permissions
PersistentDriverTestCase.php:255
it_only_clears_permissions_on_the_given_resource
PersistentDriverTestCase.php:268
it_can_clear_every_single_permission_for_a_lock_instance
PersistentDriverTestCase.php:282
it_can_toggle_multiple_permissions_at_once
PersistentDriverTestCase.php:329
it_can_check_actions_from_aliases
PersistentDriverTestCase.php:367
it_can_work_with_roles
PersistentDriverTestCase.php:402
it_can_return_allowed_resource_ids
PersistentDriverTestCase.php:452
it_can_return_denied_resource_ids
PersistentDriverTestCase.php:470
I'm grateful and happy about any feedback you can give me. Thank you for coding this very cool package.
Cheers, Christian
Is it possible to have individual users have different roles? I see that get Caller::getCallerRoles() allows you to set what role you would like to have, but that is for all User instances.
I would like for getCallerRoles() to return a different value depending on who, I'm logged in as. I would like to query the db to return this value instead of having it hard coded. When I tried this approach, I realized that caller data and role data can never be set at the same time in the lock_permissions table.
Apparently clear
is a bit too confusing to what it means. For some people it means clearing (allowing) someone to do something but it's currently implemented as removing permissions.
Any suggestions for another phrasing?
We can use $lock->allowed()
to retrieve a list of allowed resources.
How can we get the list of any available permission for a given caller?
I've just gone through the library, but didn't find any results for this one.
Is it possible to integrate caching somehow? IMO it is much more cheaper in performance to cache permission/privileges when using a persistent driver.
Not an issue but a request.
Is it possible to see a very simple sample laravel app
Thanks
This could return a collection object which could assign permissions to multiple callers or roles at once.
These things need to be done before a stable 0.1.0 can be released.
Functionality
ReadOnly
driverLock
classIssues
Questions
Documentation
Drivers
Package
CONTRIBUTORS.md
fileCHANGELOG.md
fileHi,
is there any particular reason why you only remove permission that is instance of Privilege but not Restriction?
Hi !
Is it possible to get an array of all callers and/or roles having privilege/restriction of a resource ?
For the moment, it's possible to make something like this $caller->getPersmissions()
But it would useful for me to be able to make something like this $resource->getAllowedCallers() (and the same for Roles and the same for "restriction" permission)
Hello Everyone,
I have a problem/question.
In the config there is the permissions
section and on the comments it says that this should only be used if you are using the array driver.
so my question is where am I suppose to define what the aliases are? and are they not suppose to be stored in the database if you are using the database driver?
Thank You
We have a role system whereby denial is always more important than an allow.
How can we implement this using lock?
Good Evening!
I'm opening this issue as a discussion to find out what is left for this to be tagged as 1.0 stable? This pr ( #42 ) exists to provide an easy transition path to that in the interim but it would be great to get this 1.0-stable
:)
E.g. ->can('read', 'post', 8)
instead of ->can('read', 'posts', 8)
.
Or is that just overkill?
Consider the following url:
/users/1/tasks/2
I want to ensure that only the user with an id of 1 can get to their specific task.
I would also like to have a super admin (let's say that user as an id of 8) be able to access both
/users/8/tasks/4
and
/users/1/tasks/2
The super admin can access any task. Standard users that go to a task that isn't their own will get denied.
Is there a fetchOwn('tasks') method or a similar way to implement the example above?
I think it would be better to be able to flush drivers at some point instead of updating them all upon request. This would allow saving roles at once. With a good ORM behind all queries to the database are optimized for the best performance.
The word "resource" is not soft reserved in PHP 7. We better find some other name for it to avoid conflicts in future versions.
$manager->caller($caller)->sync(array $actions, $resource = null, $resourceId = null);
This will remove all allowed permissions which aren't in the $actions
list and add allowed permissions which are in the $actions
list. Could be useful when you need to change all of the actions at once,
Currently the interfaces are in their own namespace Contracts
. I believe each of these interfaces should be in the namespace where they belong.
For instance, the Caller
interface and InvalidCaller
exception should be in the Callers
namespace. This adds more cohesion in the package and removes generic namespaces. Think about one namespace to rule them all
. It makes it simpler. Classes inside the Callers
namespace will no longer have to imported and when you look inside the namespace everything is nicely packed together.
Having them in a separate namespace, in my opinion, is a smell and feels like something is leaking.
Anyhow, this is my 2 cents. Do with it what you like!
Cheers
Would it make sense to implement a clear
method for a lock instance to clear any matching permissions, either privileges or restrictions? This could be an easy way to clear permissions to get a fresh start. But I'm not sure if it would be very useful for many people.
The api would be:
public function clear(
string|array $action,
string|\BeatSwitch\Lock\Contracts\Resource $resource = null,
int $resourceId = null
)
Thoughts?
See https://getcomposer.org/doc/articles/aliases.md#branch-alias
So that package can be installed as 1.0@dev instead of dev-master.
If this isn't maintained anymore, you should probably set it to abandoned on packagist :)
https://packagist.org/packages/beatswitch/lock
I'm not happy with suffixing traits with Trait. It's not very expressive. Perhaps one of the following?
CallerAware
LockAware
AclAware
Preference? Suggestions?
See #29.
There seems to be one thing missing from this library that I miss from most ACL implementations but which IMHO is important for developers: Getting a list of resource IDs.
Imagine I have a couple of hundred users and a couple of thousand events. Right now it seems that the only way to get a list of events that a user can access is to load them all and check them in a loop. That is terribly inefficient.
I would like a method like this:
$lock->find('update', 'events'); // returns array of event IDs the caller is allowed to update
I'm thinking about splitting these contracts so people can optionally implement the RoleDriver
contract. This allows them to not specifically have to user the role functionality.
This could get messy if we also do #4 since we would have 4 interfaces that way.
Thoughts?
This is an important one. Currently it's so that a top level allow or deny clears any lower level privilege or restriction. So for example, when you allow only an an action of create
you basically get permission to create everything (every resource). It will also clear any restrictions in place for any resource where you wouldn't be allowed to create anything.
Practical example:
// Deny a caller from creating users and events.
$lock->deny('create', 'users');
$lock->deny('create', 'events');
// Allow the caller to create everything. After this he can both create users and events again.
$lock->allow('create');
This is the way I deem it to be logic but I don't know if the majority of you also thinks this is the logical way to do something.
Any thoughts or concerns that may arise? This is something I really want to tackle as early as possible so please give enough feedback on this.
Also: if you at any point find the current Acl not to behave in the way that makes sense for you then please tell me here so we can clear things out and improve it or make it more clear in the docs how things work.
the allowed method only return explicit resource -> it doesn't return resources allowed to role that a caller inherits.
Ie :
Role ABC has privilege on Resource 1
And
Caller XYZ has privilege on Resource 2
And
Caller XYZ has Role ABC
when I make : $lock->caller($caller)->allowed(xxxx), it returns only [Resource 2]
Maybe I missed it in the README, but how would you go about allowing a role/caller to only allow something based on an assertion (function, method, etc)? Like if you have a user/role, and you only want to allow them editing their own posts. I see the example of using a static integer, but not sure how you could instead do something like this. Just wondering.
Thank you.
I've currently created a ReadOnlyDriver
but something tells me I could best split up the Driver interface into a Driver\Read
and a Driver\Write
and require the developer to optionally implement the write one. This would make it easier to set up a Lock instance which is only used for reading permissions from a storage.
Good idea?
Is there a DB Schema? I can't seem to find it in this Repo...
Well i wrote a driver for Doctrine and thought I must have made a strange mistake. But it turns out that this error also happens with the ArrayDriver:
$manager->role('somegroup')->allow('update', 'jobs');
$manager->role('somegroup')->allow('create', 'jobs');
$manager->role('somegroup')->deny('update', 'jobs', 42);
In my logic this should only deny the resource "42" but the drivers removeRolePermission
method receives a Permission
object without a resource_id
so it deletes the entire permission.
$this->assertTrue($manager->role('somegroup')->can('create', 'jobs')); // is true
$this->assertTrue($manager->role('somegroup')->can('update', 'jobs', 1)); // is false
$this->assertFalse($manager->role('somegroup')->can('update', 'jobs', 42)); // is false
Did i got something wrong?
I don't really like the Security component in Symfony, because I think it is overcomplicated. One feature I really like though is the Voter next to ACL access checking:
The Laravel lock uses a single table, see this file. But the example implementation in the readme.md shows two tables. Why? And why would I use the two tables instead of the single table from the Laravel plugin?
I'm asking because I'm building a CakePHP 3.0 plugin which has been so far surprisingly easy because the ORM is almost the same as Laravals. I copied the Laravel driver and started adapting the code and I think I'm already done with the very basics (test aside). My only show stopper right now is if I should or have to use one or two tables for a better implementation.
Edit: After reading the code a little more I guess the two table solutions would be better because I can see that the driver interface features Role and Caller methods? So I assume the methods that have Role in their name should use the roles table and the other methods the callers table? Is that how it is thought?
any estimate wwhen thats done?
I've come to the conclusion that it would be nice if resources could inherit permissions from other resources. For example, take a contact entity. The contact could be either a person or a company. I want a caller or a role to both be able to create persons and companies but they should only be able to edit a person record and not a company. Currently this would be solved by doing the following:
$manager->caller($user)->allow('create', 'person');
$manager->caller($user)->allow('create', 'company');
$manager->caller($user)->allow('edit', 'person');
By allowing for permission inheritance through resources I could add a new method to the Resource
interface called getInheritedResource
which would return the resource type from which the resource inherits permissions from. So a Person
entity could look like this:
<?php
use BeatSwitch\Lock\Resources\Resource
class Person extends Contact implements Resource
{
private $id;
public function getResourceType()
{
return 'person';
}
public function getResourceId()
{
return $this->id;
}
public function getInheritedResource()
{
return parent::getResourceType();
}
}
And now it's easy to set permissions on a parent resource type and reducing the number of calls we have to make:
$manager->caller($user)->allow('create', 'contact');
$manager->caller($user)->allow('edit', 'person');
What do you guys think about this?
Let's say I have three roles: Admin, Editor, User.
Admin can edits everyone's posts.
Editor can edits everyone's posts except admin's.
User can only edits their own posts.
id | author | content |
---|---|---|
1 | ImUser | foobar. |
2 | ImEditor | hello, world! |
3 | ImAdmin | Hi! |
username | rank |
---|---|
ImUser | user |
ImEditor | editor |
ImAdmin | admin |
Insert a new row each time the user create a post,
ImUser and ImEditor created the post, so they got the permission to edit their own post.
username | action | resource_type | resource_id |
---|---|---|---|
ImUser | edit | posts | 1 |
ImEditor | edit | posts | 2 |
Admin can edit any posts so we set the resource_id
as null.
The row of the editor one has been inserted after ImUser created the post,
so editor has the permission to edit the post #1.
role | action | resource_type | resource_id |
---|---|---|---|
admin | edit | posts | NULL |
editor | edit | posts | 1 |
So If I want to create a new role named 'moderator' for example,
and moderator should've the permission to edit editor and user's posts,
but because we added the role after ImUser and ImEditor created their posts (#1 and #2)
now moderator has no permission to edit the post #1 and #2, how can I solve this problem?
And won't it be such a mess If I do really use this structure?
Think about this if I have many roles and posts:
role | action | resource_type | resource_id |
---|---|---|---|
admin | edit | posts | NULL |
admin | remove | posts | NULL |
editor | edit | posts | 1 |
editor | remove | posts | 1 |
moderator | edit | posts | 1 |
moderator | remove | posts | 1 |
.. and many rows ..
1.How do I fix the permission problem?
2.Is it bad to use this structure or everyone use it like this?
It's my first time to use the ACL system, any ideas even not an answer would be appreciated.
Currently the Manager class accepts a single driver to store all permissions. I was thinking about allowing multiple drivers to be set. So some can be ready only with the storePermission
and deletePermission
methods not do anything on a read-only driver. But then you can do things like:
$manager->driver('production')->caller($caller)->can(...)
$manager->driver('local')->caller($user)->can(...)
This makes it easy to determine permissions locally for production settings.
Would this be a nice to have?
I can create a role by doing:
LockManager::role('auth-user')->allow('create', 'tasks');
That will be the equivalent of a database insert statement
//only auth-user's can create tasks
DB::table('lock_permissions')->insert(
[
'caller_type' => null,
'caller_id' => null,
'role' => 'auth-user',
'type' => 'privilege',
'action' => 'create',
'resource_type' => 'tasks',
'resource_id' => null,
]
);
That makes sense.
I can create user a permission by doing:
LockManager::caller($user)->allow('create', 'tasks');
That would be an insert equivalent of (assuming the user has an id of 1):
//user with id of 1 can create tasks
DB::table('lock_permissions')->insert(
[
'caller_type' => 'users',
'caller_id' => 1,
'role' => '', //notice that user doesn't have a role name
'type' => 'privilege',
'action' => 'create',
'resource_type' => 'tasks',
'resource_id' => null,
]
);
That makes since to me too.
Where things break down for me is when I want to create the auth-user role above but then attach multiple users to that role. It's repetitive to have individual user permissions that each allow access to create tasks.
Is that possible to do using this package? If so, could you provide an example of how to attach roles to users?
The other thing that really confused me was the use of
\BeatSwitch\Lock\Callers\Caller::getCallerRoles()
In the example you had this method return a static array ie) ['editor', 'publisher']. I would think that the getCallRoles() method would query the lock_permissions table and grab all the roles for that caller instance.
The caller
method currently instantiates a new BeatSwitch\Lock\Lock
instance but I think this method isn't expressive enough and it's not really clear what it does. At the same time I'm not a big fan of getCallerAcl
.
Thoughts?
Reference: https://github.com/BeatSwitch/lock/blob/master/src/Manager.php#L28
Is there a way to return a list of all privileges and/or restrictions on a given caller?
I'd like to return a list of the logged in user's permissions so I can display/edit them in an admin panel, and I can't see a way to easily retrieve all permissions.
Thanks!
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.