3

I am currently working a REST API design and I am looking for a way to add an advanced ACL management, beyond what

Let's consider for instance that I have a route which is the following :

/profile/{user}

Let's say this route might be call with GET or PUT methods. The GET method have to a controller to display the user profile, while the PUT method should be used to update the matching user profile data.

With standard ACL, as most of the libraries provide, it is easy to define the something like :

/profile/{user} , GET -> Role::*

/profile/{user} , PUT -> Role::user

which means that the method GET for the route does not requires any role and is "public", while the method PUT method is only available if the client has the role user.

Now, I would like to enrich this mechanism to control the exact identity of the user. In fact, it seems logical that only the owner of an account can edit the profile, not the other users, and given the previous rules, nothing forbids it unless a further checking is done (typically in controller).

My suggestion is to be able to write rules like this :

/profile/{user} , PUT -> Role::user, Session::user == {user}

This way, to access this route, the current user must have the user role but the user's id have to be the same than the parameter of the route. This also could be extended more generally, for example with a post data model that would be posts in an application, in which all posts have an author (which is an user) and only authors may edit their own posts :

/post/{post} , PUT -> Role::user, Session::user == {post}.author

I know such practices are discouraged by some people who claim that this is more business logic than simple access security logic but I don't agree.

Considering I am planning to develop a library to manage such advanced ACL, I would like to know what do you think about this way of thinking and if you know some frameworks or applications that already use such mechanism.

ibi0tux
  • 241
  • 2
  • 11
  • `I would like to know what do you think about this way of thinking`. I think I have done this ... In every single project I have worked with. But this doesn't make the practice better nor worse. It just fit my needs of authorization. – Laiv Nov 26 '16 at 20:57
  • All the libraries or framework I found do not offer a such advanced control system and require a additionnal checking within the controllers. – ibi0tux Nov 26 '16 at 21:10
  • I have never implemented authorization in that way. I just extended the security Framework. With its own mechanims. Are you expecting Frameworks to fit every single detail implementation of your system? They wont, but you can extend them – Laiv Nov 26 '16 at 21:49
  • I am not expecting the framework to fit my needs, but I am thinking about something like using a callback as complementary rule in which I could write my own conditions. – ibi0tux Nov 26 '16 at 21:59
  • Then you are mixing concerns. Controller should be agnostic to the security. You are looking at the wrong place. Otherwise, ppl is right, it would be business rules. – Laiv Nov 26 '16 at 22:02
  • "Controller should be agnostic to the security" : That's the point. I agree with that, but it seems a lot of framework are not built on this principle. For instance in Symfony2 (this is just a random example I take since I recently worked with) you define access rules in the security configuration with the roles for each route, but you can not define advanced rules like the one I mentionned in my post. These additionnal tests (in the user the owner of the resource) have to be checked in the controller. – ibi0tux Nov 26 '16 at 22:08
  • But we both agreed with the problem is not the controller. You should look for security Framework that allow you to extend it. If possible, totally ignorant of the mvc so you can keep separated concerns and also decoupled. Something that Symphony seems not to be. – Laiv Nov 26 '16 at 22:14
  • Anyways, everything is leading us to two possible questions: 1. You are asking for opinions. 2. You are asking for libs or framework. In any case both are off-topic. – Laiv Nov 26 '16 at 22:17
  • "You should look for security Framework that allow you to extend it" : Perhaps my post wasn't really clear but that's what I was asking first. I am not asking for opinions nor frameworks ... I was just asking if this way of thinking has lead to real projects because I have been unable to find any security framework relying on this mechanism. – ibi0tux Nov 26 '16 at 22:20
  • 1
    There are such projects and even products in this space. Look into attribute based access control or ABAC. It provides a rule language that can express different types of access logic based on any number of attributes and relations e.g. ownership – David Brossard Nov 27 '16 at 15:05

1 Answers1

1

Part of the pain you feel with securing your API is that it has the wrong level of granularity. If you need to allow a user to "update user's own profile", then you should expose that specific operation on the API distinct from "update (any) user's profile". The client application should call the appropriate operation. Then you can check for permission to do that operation in a declarative way and deny it at the security border before it gets into controller code.

For example: If the client requests PUT /api/<update (any) user's profile> { profileid: ... }. You search their permissions (e.g. claims) for "update (any) user's profile". Failing to find it, they are denied at the security border. Whereas they might be allowed to "update user's own profile", so a PUT /api/<update user's own profile> {...} would be passed to the controller for that operation. You won't even have to specify a target profile id for this operation, because you can get it from their auth data.

REST is not simply exposing your database over HTTP nor mapping HTTP verbs to CRUD operations (or at least it shouldn't be). An API is there to focus clients on the higher-level operations. Looking at it that way also makes it easier to secure... you secure on the operation, not specific data changes.

Note: I intentionally didn't use specific naming conventions for the profile operations above. I'll leave it to someone else to argue the proper conventions for non-entity REST endpoints.

Here's another answer I did recently that may help you.

Kasey Speakman
  • 4,341
  • 19
  • 26
  • Thank you for your answer. I recently stumbled upon Laravel and its policy managements : https://laravel.com/docs/5.1/authorization#policies and this is very similar to what I was looking for. I don't see why `PUT /api/` is wrong considering if the parameter matches the current user is will be successful and there might be cases, e.g. if the current user is an admin and is allowed to edit any profile, we want it to work anyway. – ibi0tux Feb 01 '17 at 19:32
  • More generally, I don't see why an API can't be `database expose + policies`. Why is this design wrong ? I don't see more security flaws than with a regular REST API and it seems a lot easier to implement. – ibi0tux Feb 01 '17 at 19:36
  • In the linked answer, I go into some of the details as to why an API should not be a simple wrapper for database access. It starts off seeming okay, but over time introduces a lot of accidental complexity. Doing so makes every layer of your application (and all clients) concerned with low level database implementation details. In the long run, it's more maintainable if all parties involved focus on the "business semantics" of what's happening. It also causes soft problems when devs only speak DB details to a user asking business questions. – Kasey Speakman Feb 01 '17 at 20:21