Merge pull request #2673 from strongloop/fix/acl-related-model-resolution-2x

Fix acl related model resolution
This commit is contained in:
Miroslav Bajtoš 2016-08-25 12:43:25 +02:00 committed by GitHub
commit f99e1a0242
5 changed files with 53 additions and 11 deletions

View File

@ -394,7 +394,9 @@ module.exports = function(ACL) {
*/ */
ACL.checkAccessForContext = function(context, callback) { ACL.checkAccessForContext = function(context, callback) {
var registry = this.registry; var self = this;
self.resolveRelatedModels();
var roleModel = self.roleModel;
if (!(context instanceof AccessContext)) { if (!(context instanceof AccessContext)) {
context = new AccessContext(context); context = new AccessContext(context);
@ -417,11 +419,9 @@ module.exports = function(ACL) {
var req = new AccessRequest(modelName, property, accessType, ACL.DEFAULT, methodNames); var req = new AccessRequest(modelName, property, accessType, ACL.DEFAULT, methodNames);
var effectiveACLs = []; var effectiveACLs = [];
var staticACLs = this.getStaticACLs(model.modelName, property); var staticACLs = self.getStaticACLs(model.modelName, property);
var self = this; self.find({where: {model: model.modelName, property: propertyQuery,
var roleModel = registry.getModelByType(Role);
this.find({where: {model: model.modelName, property: propertyQuery,
accessType: accessTypeQuery}}, function(err, acls) { accessType: accessTypeQuery}}, function(err, acls) {
if (err) { if (err) {
if (callback) callback(err); if (callback) callback(err);
@ -507,10 +507,10 @@ module.exports = function(ACL) {
ACL.resolveRelatedModels = function() { ACL.resolveRelatedModels = function() {
if (!this.roleModel) { if (!this.roleModel) {
var reg = this.registry; var reg = this.registry;
this.roleModel = reg.getModelByType(loopback.Role); this.roleModel = reg.getModelByType('Role');
this.roleMappingModel = reg.getModelByType(loopback.RoleMapping); this.roleMappingModel = reg.getModelByType('RoleMapping');
this.userModel = reg.getModelByType(loopback.User); this.userModel = reg.getModelByType('User');
this.applicationModel = reg.getModelByType(loopback.Application); this.applicationModel = reg.getModelByType('Application');
} }
}; };

View File

@ -152,6 +152,34 @@ describe('access control - integration', function() {
}); });
describe('/banks', 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.beforeEach.givenModel('bank');
lt.it.shouldBeAllowedWhenCalledAnonymously('GET', '/api/banks'); lt.it.shouldBeAllowedWhenCalledAnonymously('GET', '/api/banks');
@ -173,6 +201,7 @@ describe('access control - integration', function() {
lt.it.shouldBeDeniedWhenCalledAnonymously('DELETE', urlForBank); lt.it.shouldBeDeniedWhenCalledAnonymously('DELETE', urlForBank);
lt.it.shouldBeDeniedWhenCalledUnauthenticated('DELETE', urlForBank); lt.it.shouldBeDeniedWhenCalledUnauthenticated('DELETE', urlForBank);
lt.it.shouldBeDeniedWhenCalledByUser(CURRENT_USER, 'DELETE', urlForBank); lt.it.shouldBeDeniedWhenCalledByUser(CURRENT_USER, 'DELETE', urlForBank);
lt.it.shouldBeAllowedWhenCalledByUser(SPECIAL_USER, 'DELETE', urlForBank);
function urlForBank() { function urlForBank() {
return '/api/banks/' + this.bank.id; return '/api/banks/' + this.bank.id;

View File

@ -22,6 +22,12 @@
"permission": "ALLOW", "permission": "ALLOW",
"principalType": "ROLE", "principalType": "ROLE",
"principalId": "$everyone" "principalId": "$everyone"
},
{
"accessType": "WRITE",
"permission": "ALLOW",
"principalType": "ROLE",
"principalId": "$dynamic-role"
} }
], ],
"properties": {} "properties": {}

View File

@ -5,7 +5,10 @@
var loopback = require('../../../..'); var loopback = require('../../../..');
var boot = require('loopback-boot'); var boot = require('loopback-boot');
var app = module.exports = loopback({ localRegistry: true }); var app = module.exports = loopback({
localRegistry: true,
loadBuiltinModels: true
});
boot(app, __dirname); boot(app, __dirname);

View File

@ -5,7 +5,11 @@
var loopback = require('../../../../index'); var loopback = require('../../../../index');
var boot = require('loopback-boot'); var boot = require('loopback-boot');
var app = module.exports = loopback({ localRegistry: true }); var app = module.exports = loopback({
localRegistry: true,
loadBuiltinModels: true
});
app.enableAuth(); app.enableAuth();
boot(app, __dirname); boot(app, __dirname);
app.use(loopback.token({model: app.models.AccessToken})); app.use(loopback.token({model: app.models.AccessToken}));