From 216fee30156832bef96a25c8cd6515ad725b23b1 Mon Sep 17 00:00:00 2001 From: Ritchie Martori Date: Fri, 6 Dec 2013 17:04:47 -0800 Subject: [PATCH] Add access type checking --- lib/models/acl.js | 5 ++++- lib/models/model.js | 53 ++++++++++++++++++++++++++++++++++++++++----- test/model.test.js | 29 +++++++++++++++++++++++++ 3 files changed, 81 insertions(+), 6 deletions(-) diff --git a/lib/models/acl.js b/lib/models/acl.js index 3c6661f4..918fcfbe 100644 --- a/lib/models/acl.js +++ b/lib/models/acl.js @@ -361,11 +361,14 @@ ACL.checkAccessForToken = function(token, model, modelId, method, callback) { if(token.appId) { principals.push({principalType: ACL.APPLICATION, principalId: token.appId}); } + + var modelCtor = loopback.getModel(model); + var context = { principals: principals, model: model, property: method, - accessType: ACL.EXECUTE, + accessType: modelCtor._getAccessTypeForMethod(method), id: modelId }; ACL.checkAccess(context, function(err, access) { diff --git a/lib/models/model.js b/lib/models/model.js index 72a22799..33461d97 100644 --- a/lib/models/model.js +++ b/lib/models/model.js @@ -20,11 +20,6 @@ Model.shared = true; Model.setup = function () { var ModelCtor = this; - // each model has its - // own access control - // list - ModelCtor.acl = []; - ModelCtor.sharedCtor = function (data, id, fn) { if(typeof data === 'function') { fn = data; @@ -138,6 +133,54 @@ Model.checkAccess = function(token, modelId, method, callback) { ACL.checkAccessForToken(token, this.modelName, modelId, methodName, callback); }; +/** + * Determine the access type for the given `RemoteMethod`. + * + * @api private + * @param {RemoteMethod} method + */ + +Model._getAccessTypeForMethod = function(method) { + if(typeof method === 'string') { + method = {name: method}; + } + assert( + typeof method === 'object', + 'method is a required argument and must be a RemoteMethod object' + ); + + var ACL = getACL(); + + switch(method.name) { + case'create': + return ACL.WRITE; + case 'updateOrCreate': + return ACL.WRITE; + case 'upsert': + return ACL.WRITE; + case 'exists': + return ACL.READ; + case 'findById': + return ACL.READ; + case 'find': + return ACL.READ; + case 'findOne': + return ACL.READ; + case 'destroyById': + return ACL.WRITE; + case 'deleteById': + return ACL.WRITE; + case 'removeById': + return ACL.WRITE; + case 'count': + return ACL.READ; + break; + default: + return ACL.EXECUTE; + break; + } +} + // setup the initial model Model.setup(); diff --git a/test/model.test.js b/test/model.test.js index 33d81ed9..fe74b62b 100644 --- a/test/model.test.js +++ b/test/model.test.js @@ -1,3 +1,5 @@ +var ACL = require('../').ACL; + describe('Model', function() { var User, memory; @@ -552,6 +554,33 @@ describe('Model', function() { }); + describe('Model.checkAccessTypeForMethod(remoteMethod)', function () { + shouldReturn('create', ACL.WRITE); + shouldReturn('updateOrCreate', ACL.WRITE); + shouldReturn('upsert', ACL.WRITE); + shouldReturn('exists', ACL.READ); + shouldReturn('findById', ACL.READ); + shouldReturn('find', ACL.READ); + shouldReturn('findOne', ACL.READ); + shouldReturn('destroyById', ACL.WRITE); + shouldReturn('deleteById', ACL.WRITE); + shouldReturn('removeById', ACL.WRITE); + shouldReturn('count', ACL.READ); + shouldReturn('unkown-model-method', ACL.EXECUTE); + + function shouldReturn(methodName, expectedAccessType) { + describe(methodName, function () { + it('should return ' + expectedAccessType, function() { + var remoteMethod = {name: methodName}; + assert.equal( + User._getAccessTypeForMethod(remoteMethod), + expectedAccessType + ); + }); + }); + } + }); + // describe('Model.hasAndBelongsToMany()', function() { // it("TODO: implement / document", function(done) { // /* example -