rest icon indicating copy to clipboard operation
rest copied to clipboard

constrain users access to only their own personal data

Open jay-jlm opened this issue 9 years ago • 5 comments

Regarding user access endpoints ( not related to admin/masterkey):

Correct me if I'm wrong, but it looks to me that the authentication and routing code currently has no built in mechanism for pŕeventing an authenticated user from accessing data related to other users by simply leveraging querymen to make queries that pass some other user's id ?

Hopefully I just failed to locate this, but in case it really doesn't exist, and because this is such a common requirement, it would be great to include a build-in mechanism for this so that this functionality could be activated by just adding an item or attribute ( could be named something like requireOwnId or ownerOnly ) to a route's middleware chain.

jay-jlm avatar Oct 21 '16 14:10 jay-jlm

I don't know if I got it. Can you list some requests, the expected and the actual behavior? Something like this:

  • Request: GET /users/123 authenticated as user 456
  • Exptected: don't receive anything
  • Actual: received id, picture and name.

So I can understand better and see if this is a bug.

diegohaz avatar Oct 21 '16 15:10 diegohaz

Ok, I eventually found it as a utility function inside of response/index.js called authorOrAdmin.

However I'd much rather have it as a pluggable middleware that I could apply at the route level like this:

router.put('/:id',
  authorOrAdmin(),
  token({ required: true }),
  body({ name, image, favorites, history }),
  update)

To have it as a configuration at the route level would provide much better separation of concerns between the permissions logic and the other parts of the code and that how I see it done in most security libraries such as: https://github.com/deitch/cansecurity

It would also be very nice to have the generator ask me if the 2 GET endpoints (listing and details) are available only to the author or to any authenticated user.

To give you example scenarios... a GET posts/ and GET post/:id endpoint would be usually available to any authenticated user, however a GET history/:id and GET preferences/:id endpoint would not be because they'd be part of a users own private data set.

jay-jlm avatar Oct 21 '16 17:10 jay-jlm

authorOrAdmin needs two things:

  • the current user who made the request;
  • the fetched resource to compare the user with the author field.

The current user is passed by the passport middleware (token({ required: true })), so authorOrAdmin must be called after that.

router.put('/:id',
  token({ required: true }),
  authorOrAdmin(),
  body({ name, image, favorites, history }),
  update)

But the resource is only fetched inside the controller method update, thus authorOrAdmin is there.

To have this as a middleware we need to create another middleware just to fetch the resource, something like this:

router.put('/:id',
  token({ required: true }),
  body({ name, image, favorites, history }),
  fetchResourceAndPassToReq(),
  notFound(),
  authorOrAdmin(),
  update)

I don't like it very much, but if you change the code to something like this, please share with us. :)

diegohaz avatar Oct 21 '16 17:10 diegohaz

Yes, I agree it may not be trivial to do. I expanded my comments and fixed the link to a library that implements it at routing level. See another example of it implemented at the route level here: http://stackoverflow.com/a/24302705/6771649

I'm not so sure that 2 additional middleware would really be needed in order to accomplish this. Why not have the route level middleware only set a flag on the request object and use the existing downstream middleware to execute the actual validation based on the provided flags?

jay-jlm avatar Oct 21 '16 17:10 jay-jlm

Hi, @jay-jlm I still don't understand how you solved this. I am currently facing the same problem, please assist

UrbanSwati avatar Feb 10 '18 09:02 UrbanSwati