Casl: mongoose `.orFail()` does not work when permissions are implicitly denied

Created on 26 Aug 2019  路  5Comments  路  Source: stalniy/casl

I ran into this issue accidentally today, but the way my application is set up, it expends models not found to throw an error.

ex:

    var user = await User.findById(req.params.id)
      .accessibleBy(req.ability)
      .orFail();

    res.json({ user });

When the permission to view users is set, it works fine and dandy. The conditions for this query were { _id: '5d600d0ea21964033b4fc1bb', '$and': [ {} ] }.

But if the permission is implicitly denied, the conditions are { _id: '5d600d0ea21964033b4fc1bb', __forbiddenByCasl__: 1 }. The problem is though that the user variable is returning null, and not throwing an exception.

bug casmongoose

All 5 comments

Could you please show the implementation of orFail function?

Query.prototype.orFail = function(err) {
  this.map(res => {
    switch (this.op) {
      case 'find':
        if (res.length === 0) {
          throw _orFailError(err, this);
        }
        break;
      case 'findOne':
        if (res == null) {
          throw _orFailError(err, this);
        }
        break;
      case 'update':
      case 'updateMany':
      case 'updateOne':
        if (get(res, 'result.nModified') === 0) {
          throw _orFailError(err, this);
        }
        break;
      case 'findOneAndDelete':
        if (get(res, 'lastErrorObject.n') === 0) {
          throw _orFailError(err, this);
        }
        break;
      case 'findOneAndUpdate':
      case 'findOneAndReplace':
        if (get(res, 'lastErrorObject.updatedExisting') === false) {
          throw _orFailError(err, this);
        }
        break;
      case 'deleteMany':
      case 'deleteOne':
      case 'remove':
        if (res.n === 0) {
          throw _orFailError(err, this);
        }
        break;
      default:
        break;
    }

    return res;
  });
  return this;
};

or you can view it at https://github.com/Automattic/mongoose/blob/b0fd1b0f9036505f1556155479d207c1fd3c4a8e/lib/query.js

Thanks, I didn't know about orFail method of mongoose Query :)

I think this is a bug but I'll need some time to confirm this.

Sorry, for the long response. So, yes it's a bug. @casl/mongoose patches mongoose.Query.prototype.exec object to prevent unnecessary request to database when it's clear that nothing will be returned.

Update: According to implementation details orFail adds additional transformation (callback function) which is applied after result from db is returned. This logic lives in exec method, that's why when user has no access the transformation doesn't work

fixed in @casl/[email protected].

Thanks for the issue!

Was this page helpful?
0 / 5 - 0 ratings

Related issues

chickenandsnake picture chickenandsnake  路  6Comments

malithrw picture malithrw  路  7Comments

LyhjeHylje picture LyhjeHylje  路  5Comments

victorsilent picture victorsilent  路  4Comments

makslevental picture makslevental  路  8Comments