Comments (18)
I was wondering about this problem too. The issue is that we the route may be dynamic. For example, we may want a user to only be able to view his own purchases. Consider:
GET /orders/:id
We don't want non-owners retrieving arbitrary orders, so we must check if this order is owned by the requesting user based on his token.
If you use a file based policy, there is currently no way to protect such a route unless you literally fill in every user in your system. Either that, or authorise in the route handler, which in my opinion is a bad idea.
The only viable option I can think of is to assign each user a unique role with corresponding unique permissions. I would then stuff the generated policy into a redis instance for fast retrieval and/or caching.
from casbin.
https://casbin.org/docs/en/function#how-to-add-a-customized-function
from casbin.
For your case, I think a way to handle access control is:
- define a function to retrieve
:id
value from/orders/:id
via regex, likegetID(r.obj, p.obj)
- define a function to compare the user with the owner of the order, like
ownOrder(r.sub, order_id)
, I suppose you will have an order struct, which has a owner property. So you can find the order with order_id, then compare user with the order's owner in the function. - At last, your Casbin matcher looks like:
m = ownOrder(r.sub, getID(r.obj, p.obj)) && regexMatch(r.act, p.act)
In this way, you won't need to store every mapping from an individual user to an order. So the policy rules can be limited in a reasonable number.
from casbin.
Then I think you don't need to use the g() function.
Model:
[request_definition]
r = sub, obj, act, role
[policy_definition]
p = obj, act
[policy_effect]
e = some(where (p.eft == allow))
[matchers]
m = (r.role == "admin" || isOwner(r.sub, r.obj, p.obj)) && regexMatch(r.act, p.act)
An example policy is:
p, /users, (GET)|(POST)
p, /users/:id, (POST)|(GET)|(PUT)|(DELETE)
from casbin.
@acim please open a new issue.
from casbin.
Casbin usually acts as a permission checker for all routes. See the web framework middlewares: https://github.com/casbin/casbin#web-frameworks
You can control access on a per route basis. Please refer to the RESTful example at: https://github.com/casbin/casbin#examples
The corresponding policy rule for your case would be:
p, alice, /posts, POST
So the user named alice
will be allowed to send POST requests to /posts
.
from casbin.
I am not sure if there is a better practice for this @hsluoyz. There will be many permissions in the database as the system grows and reads in such an enormous table might become very very slow which could mean very slow server boot time.
from casbin.
@hsluoyz thanks.
This seems to be a more scalable way. If I would like to also use RBAC, I would have to add
m = (g(r.obj, p.obj) || isOwner(r.sub, getID(r.obj, p.obj))) && regexMatch(r.act, p.act)
?
Assuming the policy looks something like
p, some/route/:id, GET
g, some/route/:id, admin
So that in this case, some/route/:id
would only be accessible to: admin role, or owner.
from casbin.
I don't think you are understanding the role function correctly. g, some/route/:id, admin
really means some/route/:id
has the role admin
. So every permission assignment (aka p policy) that works on admin
will also work on some/route/:id
. In this case, you don't have something like p, admin, GET
.
How is the admin role defined? g(r.obj, p.obj)
really means the URL path in request has the role of URL path in policy. Is this correct? Or what you refers to is really the role property for a user?
from casbin.
Sorry, I made a mistake.
Example model:
[request_definition]
r = sub, obj, act, role
[policy_definition]
p = obj, act
[role_definition]
g = _, _, # resource, role
[policy_effect]
e = some(where (p.eft == allow))
[matchers]
m = (g(r.obj, r.role) || isOwner(r.sub, r.obj, p.obj)) && regexMatch(r.act, p.act)
Example policy:
p, /users, (GET)|(POST)
p, /users/:id, (POST)|(GET)|(PUT)|(DELETE)
g, /users, admin
g, /users/:id, admin
Edit: in this case, I would store role on the user's token. I would then pass the role to the matcher in my middleware, with the user id.
Edit2: Combine the functions you suggested into one isOwner
function that takes all the necessary parameters and checks the ownership of the resource requested.
Edit3: In this case, a normal user would never be able to access /users
. But a user would be able to access /users/:id
if he is owner of that user (i.e. himself).
from casbin.
I'm even confused with the above model. You said:
some/route/:id would only be accessible to: admin role, or owner.
I believe it means that the subject (r.sub) can choose to have an admin role or not, or be an owner. But g(r.obj, r.role)
really means to determine whether the object (URL path) has a role. Also you pass in a role
in the request. I think this is unnecessary. Here's what I think would be right:
Model:
[request_definition]
r = sub, obj, act
[policy_definition]
p = sub, obj, act
[role_definition]
g = _, _
[policy_effect]
e = some(where (p.eft == allow))
[matchers]
m = (g(r.sub, p.sub) || isOwner(r.sub, getID(r.obj, p.obj))) && regexMatch(r.act, p.act)
An example policy is:
p, admin, some/route/:id, GET
p, *, another/route/:id, GET
g, alice, admin
from casbin.
I misunderstood how g(...)
works.
In this example it means I have to add all users and their roles to the policy when my app boots up. What I was trying to achieve is to determine:
a. If user's token shows he's admin, allow him to access route.
b. If not, check if he is owner
In other words, this means we want to avoid adding any users to groups. We just want to say:
/some/route/:id
is accessible to admins and owners
from casbin.
Thanks, that seems to solve my problem. Good work!
from casbin.
@iantanwx I have a need for something similar. The info on this issue thread has pointed me in the right direction, but I'd love to see an example of the implementation of your solution.
from casbin.
@iantanwx @hsluoyz Is there an example to see isOwner implementation? Or documentation on how to write custom functions? I am using python.
from casbin.
@nitinkhosla79 isOwner
is a custom function defined by yourself.
from casbin.
how does model/conf file know that where is this function defined? Please share any documentation on custom function.
.
Our scenario: A request is sent from firm A to firm B. (example private buyer and seller deal) : that deal should only be viewed by sender and receiver. New deals can be created anytime. How to express this in configuration?
[request_definition]
r = sub, obj, act, role
[policy_definition]
p = obj, act
[policy_effect]
e = some(where (p.eft == allow))
[matchers]
m = (r.role == ("sender" | "receiver") && regexMatch(r.act, p.act)
p, /users, (GET)|(POST)
p, /users/:id, (POST)|(GET)|(PUT)|(DELETE)
from casbin.
If this custom function isOwner has to access database to find out the owner, does it mean we have to access the same database record (document) again if Casbin permits access? I mean is there some way to avoid this redundant read? I thought to use Casbin as middleware (Golang).
from casbin.
Related Issues (20)
- [Bug] RoleManager's MatchingFunc Lost After Calling (*SyncedEnforcer).LoadPolicyFast HOT 2
- [Bug] json request does not support arrays HOT 3
- [Bug] Whenever I use the GetRolesForUser method, I always receive an error stating "invalid memory address or nil pointer dereference." HOT 6
- [Feature] GetImplicitPermissionsForUser optimize 99% latency by avoid using roleManager.hasLinkHelper HOT 1
- [Feature] Adapter supports ctx HOT 3
- [Question] RBAC matcher function isn't called with inherited roles HOT 1
- [Question] Condition Role Manager can support pattern domain For user -> role link HOT 3
- Error encountered when creating an Enforcer based on the ABAC model: extraneous or missing "in quoted field" HOT 2
- [Feature] support return err in GetPermissionsForUser HOT 3
- [Question] - How can I enforce hierarchy check for request to match both domain and tenant? HOT 1
- [Question] How to get permissions while using resource roles HOT 2
- [Question] How to delete role in domain HOT 2
- [Question] HOT 2
- [Question] Why doesn't DeleteRole delete role completely from the policies? HOT 1
- Issue with non-functional Chinese language switch feature on GitHub documentation HOT 1
- [Question] Why CachedEnforcer uses sync.RWMutex just like sync.Mutex? HOT 6
- [Question] Is it expected that keyMatch3 handles `*` pattern? HOT 3
- [Bug]`GetRolesForUser("userId")` will raise nil error when using RBAC with conditions. HOT 5
- [Bug] nil pointer panic when calling role related functions with no role definition model HOT 2
- [Question] Implement row-level and column-level authorization for data in DB HOT 3
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from casbin.