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 :


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.

  • 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
  • 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 Nov 27 '16 at 15:05

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.

  • Thank you for your answer. I recently stumbled upon Laravel and its policy managements : 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/<update (any) user's profile> 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 1 '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 1 '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. Feb 1 '17 at 20:21

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.