Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How should ACL work in a REST API?

A REST API is written in ExpressJs 4.x.x / NodeJS.

Let's assume an interface :

app.delete('/api/v1/users/:uid', function (req, res, next) {
...
}

So with that interface users can be deleted.

Let's assume there are 2 Customers in the system, and each Customer has Users. A User can have the privilege of deleting other Users with a role named CustomersAdmin. But this User should only be able to delete Users which are Users from his Company(Customer).

So, let's get ACL into the scene. Assuming in our ACL we can define roles, resources and permissions. (Code is adopted from http://github.com/OptimalBits/node_acl#middlware.)

app.delete('/api/v1/users/:uid', acl.protect(),  function (req, res, next)   
{
 // ? Delete User with uid = uid or check 
 // ? first if current user is in same company as user uid
}

There are two things to consider. One is protecting the route from persons without permission to HTTP/DELETE on that route ( /api/v1/users/:uid ) and the other is that a Person with Role CustomersAdmin shall not be allowed to delete Users from another Customer.

Is ACL supposed to do both? Or is it supposed to protect the route /api/v1/users?

So, would I use it like

acl.allow([
{
  roles:'CustomersAdmin',
  allows:[
   {resources:['/api/v1/users', '/api/v1/users'] permissions:'delete'}
}
app.delete('/api/v1/users/:uid',acl.middleware(3), function(req,res,next)
{
Make sure uid is a User from same Customer as request is from(req.session.userid)
}

This would allow every User with Role CustomersAdmin to delete whatever user he wants. Or is it preferable to define each possible Users route as a Resource and define multiple Roles which can interact with them?

acl.allow([
{
  roles:'CustomersAdminOne',
  allows:[
   {resources:['/api/v1/users/1', '/api/v1/users/2'], permissions:'delete'}]
},
{
  roles:'CustomersTwoAdmin',
  allows:[
    {resources:['/api/v1/users/3','/api/v1/users/4'], permissions:'delete'}
  ]
}
app.delete('/api/v1/users/:uid',acl.middleware(), function(req,res,next)
{
no logic needed to be sure that request is from a user within the same customer
}
like image 737
Schemiii Avatar asked Jun 23 '15 09:06

Schemiii


1 Answers

The way I solved this was to create a role per user. I use a mongoose post save hook:

acl.addUserRole(user._id, ['user', user._id]);

Then in a post save hook for a resource I do this:

acl.allow(['admin', doc.user._id], '/album/' + doc._id, ['*']);
acl.allow(['guest', 'user'], '/album/' + doc._id, ['get']);

You can then use the isAllowed method to check if req.user has the right permissions.

like image 116
jameslouiz Avatar answered Oct 12 '22 12:10

jameslouiz