New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Pass the resource into the getRoleId() function #14
Comments
Haven't heard from you, but I went ahead and threw together the PR for this change. Let me know if you're not into it or would like some changes |
This is interesting. Could this not be solved with a custom assertion? The assertion callback has access to the role, resource, and requested action, which means you should be able to allow or deny based on that. If custom assertions can't solve this, I'm interested to see how you're using this. |
It can be, and we are using it that way currently. There are a couple of things that are kind of clunky in our particular use case, though, when using arrays of roles. And I totally understand if our use case seems fringe and you'd rather not support it. Here's an example of a case we have that is simplified by the change in the PR: If we imagine a blog, we define a Post resource. We define 3 roles, So take this snippet:
So, using the ability to return arrays of roles from We currently support this permissions model with the assertions as they are, but it requires me to write custom assertions for all of my |
Oh, that's interesting. I hadn't thought of using roles like that. I usually think of them as things like When using them in this way, what are the actions you're passing in to the ACL? e.g.
The way I'd do this would be a little different:
Could something like this work for you? |
No, there's no natural relationship between user -> resource in my use case that I can use to determine access. I can't say "because this user created this particular post they get to edit it". I need to be able to assign posts to users explicitly. It's the case where an admin comes into the system and says "allow this member to edit these 10 posts but not these 5". So I have to link up users as editors for some blog posts and not others, but not only that I have two or three other roles that they may have that determine their access to a particular post. So I need to say something like: User:1 can edit Post:1, and User:1 can edit and delete Post:2, and User:1 can create new Posts. In order to represent this relationship I have to store some information about the relationship about this user to Post:1 and Post:2, and since (in this example) the user did not create those posts and otherwise has no natural relationship, I have to decide how to relate them. The crux is that any user can be assigned to edit any post. So I promote my "member" to "editor" and now I have to say in my assertion callback "does this person have edit privileges on this specific resource?" (this information is stored in the database). Then after that I have one more complication: I want multiple levels of privileges per Post. Not only do I want to say a user is an editor, but that user can delete also. I want the "deleter" role to inherit from the "editor" role. User:1 can be an editor on Post:1 and User:2 can be a deleter on Post:2. So I grant User:2 the deleter role and User:1 the editor role. My assertions look like this now:
In the scenario above, anybody will have the deleter role if they are allowed to delete even one Post. Now I have to make things more complicated: we have Pages as well as Posts. I also need to be able to assign users arbitrary permissions to Pages (this is why I proposed the multiple roles change). Now I need roles like this: My assertion callbacks for posts look similar to my assertion callbacks for pages. I have to check up the permissions hierarchy every time. This works, but it's not as clean as I'd like. I've lost some of the value of role inheritance. I can't just check if this user has been assigned as an editor, but I must also check if this user has been assigned as a deleter on the given resource. Now my real use case I have a lot more resources and a lot more roles. The logic in my assertions above is checking a hierarchy of 3 or 4 every time. In order to build roles in my User models Then every assertion has to re-check roles to make sure that 1, do they have edit on this thing? and 2, do they have deleter on this thing? This architecture is simplified if I have the resource available to me in the user object when I go to deliver the roles. I can simply say "oh you're checking access to Post:1? Well here is the role this user has for that resource". This results in fewer false positives (ie, executing assertion callbacks fewer times), and I never have to check up through a permissions hierarchy because I get to rely on virgen-acl to do that for me, which is desirable. Now, that all being said, I think this is a more complex use case than virgen-acl was maybe intended for, but I also think that virgen-acl was very well designed and is flexible enough to handle very complex use cases. This change helps me more cleanly support my complex use case. |
Hey @djvirgen i know i've written a lot on the topic. I'm curious if you're still not convinced. I want this change enough that I'd probably maintain a fork with this feature if you'd prefer not to merge it. Before I go through the effort, though, I wanted to check in one more time. |
Hi @spruce-bruce , After reading through your latest comments a few times, I think the issue mostly involves how you're using roles. The role name itself should not indicate any level of permission. For example, a role of This allows Virgen ACL to look up the appropriate permissions based on the provided
If Virgen ACL starts to support dynamic roles based on the resource and/or action, I think that will move too much of the access-control rules to the domain entities, which kind of defeats the purpose of an ACL. I'd prefer the roles and resources would simply identify themselves, and let the ACL determine who can do what. I hope this helps, let me know what you think. |
I think that's fair, and I completely understand the rationale. My current system is using the It does prevent me from getting the use out of role inheritance that I would like, though, since (use your example) I would only have one role. Every user in my system will have the 'user' role and the user role will be allowed to do anything to any entity and the only thing preventing that will be the logic in allow callbacks. The value of virgen-acl in such a system is negligable, then. I could remove virgen-acl and just use the logic in my allow callbacks instead of And that's fair, too. If you think that in a system like mine, where any user could potentially be given access to any resource, that virgen-acl isn't the right choice then it totally makes sense to prevent virgen-acl from moving in the direction of supporting such a system. It remains true, though, that using virgen-acl with the change in this PR allows me to simplify my app code and maintain a permissions structure that is easy to understand because of expressiveness in writing I'll just maintain a fork then for my purposes and stop harassing you about this. Thanks for getting back to me on this, and really, I like this library quite a lot. |
This is a very small technical change, but one that deserves a little bit of discussion. I'd like to pass the resource into the
getRoleId()
function on the user object.My use case is getting more complicated as the requirements for my project change. I have a structure now where a user can have different 'roles' on different resources. I can support this requirement by passing
getRoleId()
the resource and allowing thegetRoleId()
function to return different roles depending on the resource that its passed.This might be a philosophical change to how the library is intended to be used, though, so I'm curious if there are any thoughts on this change.
The text was updated successfully, but these errors were encountered: