I'm trying to find the best solution to a simple problem that is not largely discussed around.
My application have lots of users that can create and edit data. An user should only see and edit his data, not other's.
Think about Alice, who has a Restaurant A with a Menu MenuA, and Bob, who has a Restaurant B and a Menu MenuB.
I have APIs to CRUD restaurants and menus and I can easily only authorize logged users with correct claims and roles. What I want to do now is prevent Bob to access Alice's restaurant or menu, and viceversa.
For instance, Bob should be authorize to PUT /api/restaurants/B
but should be unauthorized to PUT /api/restaurants/A
or even PUT /api/restaurants/A/menus/x
A possible solution is the one provided here ASP.NET MVC Attribute to only let user edit his/her own content. This solution requires to create a custom Authorize attribute to actively check if the logged user is the proprietary of the accessed entity. The entities have an userId field to check if the user making the request is the owner of the data. This solution is nice and clean but lacks some features. Every entity in the model should have an userId field and can only be accessed by the owner OR for each entity I need to navigate to the root entity of the authorization model (ex. accessing Menu i need to query for the parent entity Restaurant to check if MenuB is inside a Restaurant owned by the user). To achieve multiple owners (ex. the restaurant managers) the logic will be a lot more complex. I am also worried about the overhead here, since basically every call requires to do some queries to check data access, but it will probably not be an issue.
Is there a best practice?
What you want do is implement attribute-based access control or abac.
In the ABAC architecture, you have the notion of a policy enforcement point (PEP) which intercepts the API call and determines whether the call should go through. The PEP converts the API call into an authorization request and sends it off to a central Policy Decision Point (PDP).
The following architecture summarizes the flow.
The PDP is configured with a set of policies that determine what is allowed and what is denied. For instance you can write policies such as:
There are two languages you can write policies in: xacml or alfa.
For instance, in ALFA, a policy would look like:
namespace restaurant{
attribute userId{
category = subjectCat
id = "restaurant.userId"
type = string
}
attribute owner{
category = resourceCat
id = "restaurant.resourceCat"
type = string
}
policy restaurant{
target clause objectType == "restaurant"
apply firstApplicable
rule ownerCanView{
target clause actionId == "view"
permit
condition userId == restaurant.owner
}
}
}
All you need is to use a XACML 3.0 Policy Decision Point. There are Java and .NET implementations as well as commercial ones. Have a look at this blog post on .Net authorization.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With