diff --git a/common/models/acl.js b/common/models/acl.js index c83bdd8f..d5958ef2 100644 --- a/common/models/acl.js +++ b/common/models/acl.js @@ -395,7 +395,9 @@ module.exports = function(ACL) { */ ACL.checkAccessForContext = function(context, callback) { - var registry = this.registry; + var self = this; + self.resolveRelatedModels(); + var roleModel = self.roleModel; if (!(context instanceof AccessContext)) { context = new AccessContext(context); @@ -418,10 +420,8 @@ module.exports = function(ACL) { var req = new AccessRequest(modelName, property, accessType, ACL.DEFAULT, methodNames); var effectiveACLs = []; - var staticACLs = this.getStaticACLs(model.modelName, property); + var staticACLs = self.getStaticACLs(model.modelName, property); - var self = this; - var roleModel = registry.getModelByType(Role); this.find({ where: { model: model.modelName, property: propertyQuery, accessType: accessTypeQuery }}, function(err, acls) { if (err) { @@ -508,10 +508,10 @@ module.exports = function(ACL) { ACL.resolveRelatedModels = function() { if (!this.roleModel) { var reg = this.registry; - this.roleModel = reg.getModelByType(loopback.Role); - this.roleMappingModel = reg.getModelByType(loopback.RoleMapping); - this.userModel = reg.getModelByType(loopback.User); - this.applicationModel = reg.getModelByType(loopback.Application); + this.roleModel = reg.getModelByType('Role'); + this.roleMappingModel = reg.getModelByType('RoleMapping'); + this.userModel = reg.getModelByType('User'); + this.applicationModel = reg.getModelByType('Application'); } }; diff --git a/test/access-control.integration.js b/test/access-control.integration.js index 1b78272a..14a9130c 100644 --- a/test/access-control.integration.js +++ b/test/access-control.integration.js @@ -142,6 +142,34 @@ describe('access control - integration', function() { }); describe('/banks', function() { + var SPECIAL_USER = { email: 'special@test.test', password: 'test' }; + + // define dynamic role that would only grant access when the authenticated user's email is equal to + // SPECIAL_USER's email + + before(function() { + var roleModel = app.registry.getModel('Role'); + var userModel = app.registry.getModel('user'); + + roleModel.registerResolver('$dynamic-role', function(role, context, callback) { + if (!(context && context.accessToken && context.accessToken.userId)) { + return process.nextTick(function() { + callback && callback(null, false); + }); + } + var accessToken = context.accessToken; + userModel.findById(accessToken.userId, function(err, user) { + if (err) { + return callback(err, false); + } + if (user && user.email === SPECIAL_USER.email) { + return callback(null, true); + } + return callback(null, false); + }); + }); + }); + lt.beforeEach.givenModel('bank'); lt.it.shouldBeAllowedWhenCalledAnonymously('GET', '/api/banks'); @@ -163,6 +191,7 @@ describe('access control - integration', function() { lt.it.shouldBeDeniedWhenCalledAnonymously('DELETE', urlForBank); lt.it.shouldBeDeniedWhenCalledUnauthenticated('DELETE', urlForBank); lt.it.shouldBeDeniedWhenCalledByUser(CURRENT_USER, 'DELETE', urlForBank); + lt.it.shouldBeAllowedWhenCalledByUser(SPECIAL_USER, 'DELETE', urlForBank); function urlForBank() { return '/api/banks/' + this.bank.id; diff --git a/test/fixtures/access-control/common/models/bank.json b/test/fixtures/access-control/common/models/bank.json index a06555b8..f31c7876 100644 --- a/test/fixtures/access-control/common/models/bank.json +++ b/test/fixtures/access-control/common/models/bank.json @@ -22,6 +22,12 @@ "permission": "ALLOW", "principalType": "ROLE", "principalId": "$everyone" + }, + { + "accessType": "WRITE", + "permission": "ALLOW", + "principalType": "ROLE", + "principalId": "$dynamic-role" } ], "properties": {} diff --git a/test/fixtures/access-control/server/server.js b/test/fixtures/access-control/server/server.js index d426aa65..02e7ab9a 100644 --- a/test/fixtures/access-control/server/server.js +++ b/test/fixtures/access-control/server/server.js @@ -5,8 +5,12 @@ var loopback = require('../../../..'); var boot = require('loopback-boot'); -var app = module.exports = loopback({ localRegistry: true }); +var app = module.exports = loopback({ + localRegistry: true, + loadBuiltinModels: true, +}); var errorHandler = require('strong-error-handler'); + boot(app, __dirname); var apiPath = '/api'; diff --git a/test/fixtures/user-integration-app/server/server.js b/test/fixtures/user-integration-app/server/server.js index de944ab1..bcd3c31a 100644 --- a/test/fixtures/user-integration-app/server/server.js +++ b/test/fixtures/user-integration-app/server/server.js @@ -5,8 +5,12 @@ var loopback = require('../../../../index'); var boot = require('loopback-boot'); -var app = module.exports = loopback({ localRegistry: true }); +var app = module.exports = loopback({ + localRegistry: true, + loadBuiltinModels: true, +}); var errorHandler = require('strong-error-handler'); + app.enableAuth(); boot(app, __dirname); app.use(loopback.token({ model: app.models.AccessToken }));