Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 20 additions & 20 deletions common/models/acl.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@

var g = require('../../lib/globalize');
var loopback = require('../../lib/loopback');
var utils = require('../../lib/utils');
var async = require('async');
var assert = require('assert');
var debug = require('debug')('loopback:security:acl');
Expand Down Expand Up @@ -321,6 +322,7 @@ module.exports = function(ACL) {
ACL.checkPermission = function checkPermission(principalType, principalId,
model, property, accessType,
callback) {
if (!callback) callback = utils.createPromiseCallback();
if (principalId !== null && principalId !== undefined && (typeof principalId !== 'string')) {
principalId = principalId.toString();
}
Expand All @@ -340,27 +342,27 @@ module.exports = function(ACL) {
debug('Permission denied by statically resolved permission');
debug(' Resolved Permission: %j', resolved);
process.nextTick(function() {
if (callback) callback(null, resolved);
callback(null, resolved);
});
return;
return callback.promise;
}

var self = this;
this.find({where: {principalType: principalType, principalId: principalId,
model: model, property: propertyQuery, accessType: accessTypeQuery}},
function(err, dynACLs) {
if (err) {
if (callback) callback(err);
return;
return callback(err);
}
acls = acls.concat(dynACLs);
resolved = self.resolvePermission(acls, req);
if (resolved && resolved.permission === ACL.DEFAULT) {
var modelClass = self.registry.findModel(model);
resolved.permission = (modelClass && modelClass.settings.defaultPermission) || ACL.ALLOW;
}
if (callback) callback(null, resolved);
return callback(null, resolved);
});
return callback.promise;
};

ACL.prototype.debug = function() {
Expand Down Expand Up @@ -388,6 +390,7 @@ module.exports = function(ACL) {
*/

ACL.checkAccessForContext = function(context, callback) {
if (!callback) callback = utils.createPromiseCallback();
var self = this;
self.resolveRelatedModels();
var roleModel = self.roleModel;
Expand Down Expand Up @@ -417,10 +420,7 @@ module.exports = function(ACL) {

this.find({where: {model: model.modelName, property: propertyQuery,
accessType: accessTypeQuery}}, function(err, acls) {
if (err) {
if (callback) callback(err);
return;
}
if (err) return callback(err);
var inRoleTasks = [];

acls = acls.concat(staticACLs);
Expand Down Expand Up @@ -452,20 +452,18 @@ module.exports = function(ACL) {
});

async.parallel(inRoleTasks, function(err, results) {
if (err) {
if (callback) callback(err, null);
return;
}
if (err) return callback(err, null);

var resolved = self.resolvePermission(effectiveACLs, req);
if (resolved && resolved.permission === ACL.DEFAULT) {
resolved.permission = (model && model.settings.defaultPermission) || ACL.ALLOW;
}
debug('---Resolved---');
resolved.debug();
if (callback) callback(null, resolved);
return callback(null, resolved);
});
});
return callback.promise;
};

/**
Expand All @@ -480,7 +478,7 @@ module.exports = function(ACL) {
*/
ACL.checkAccessForToken = function(token, model, modelId, method, callback) {
assert(token, 'Access token is required');

if (!callback) callback = utils.createPromiseCallback();
var context = new AccessContext({
accessToken: token,
model: model,
Expand All @@ -490,12 +488,10 @@ module.exports = function(ACL) {
});

this.checkAccessForContext(context, function(err, access) {
if (err) {
if (callback) callback(err);
return;
}
if (callback) callback(null, access.permission !== ACL.DENY);
if (err) callback(err);
else callback(null, access.permission !== ACL.DENY);
});
return callback.promise;
};

ACL.resolveRelatedModels = function() {
Expand All @@ -515,6 +511,7 @@ module.exports = function(ACL) {
* @param {Function} cb Callback function
*/
ACL.resolvePrincipal = function(type, id, cb) {
cb = cb || utils.createPromiseCallback();
type = type || ACL.ROLE;
this.resolveRelatedModels();
switch (type) {
Expand All @@ -536,6 +533,7 @@ module.exports = function(ACL) {
cb(err);
});
}
return cb.promise;
};

/**
Expand All @@ -546,6 +544,7 @@ module.exports = function(ACL) {
* @param {Function} cb Callback function
*/
ACL.isMappedToRole = function(principalType, principalId, role, cb) {
cb = cb || utils.createPromiseCallback();
var self = this;
this.resolvePrincipal(principalType, principalId,
function(err, principal) {
Expand All @@ -568,5 +567,6 @@ module.exports = function(ACL) {
});
});
});
return cb.promise;
};
};
35 changes: 35 additions & 0 deletions test/acl.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,41 @@ describe('security scopes', function() {
});

describe('security ACLs', function() {
it('supports checkPermission() returning a promise', function() {
return ACL.create({
principalType: ACL.USER,
principalId: 'u001',
model: 'testModel',
property: ACL.ALL,
accessType: ACL.ALL,
permission: ACL.ALLOW,
})
.then(function() {
return ACL.checkPermission(ACL.USER, 'u001', 'testModel', 'name', ACL.ALL);
})
.then(function(access) {
assert(access.permission === ACL.ALLOW);
});
});

it('supports checkAccessForContext() returning a promise', function() {
var testModel = ds.createModel('testModel', {
acls: [
{principalType: ACL.USER, principalId: 'u001',
accessType: ACL.ALL, permission: ACL.ALLOW},
],
});

return ACL.checkAccessForContext({
principals: [{type: ACL.USER, id: 'u001'}],
model: 'testModel',
accessType: ACL.ALL,
})
.then(function(access) {
assert(access.permission === ACL.ALLOW);
});
});

it('should order ACL entries based on the matching score', function() {
var acls = [
{
Expand Down
14 changes: 14 additions & 0 deletions test/role.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -539,6 +539,13 @@ describe('role model', function() {
});
});

it('supports ACL.resolvePrincipal() returning a promise', function() {
return ACL.resolvePrincipal(ACL.USER, user.id)
.then(function(u) {
expect(u.id).to.eql(user.id);
});
});

it('should resolve user by id', function(done) {
ACL.resolvePrincipal(ACL.USER, user.id, function(err, u) {
if (err) return done(err);
Expand Down Expand Up @@ -589,6 +596,13 @@ describe('role model', function() {
});
});

it('supports ACL.isMappedToRole() returning a promise', function() {
return ACL.isMappedToRole(ACL.USER, user.username, 'admin')
.then(function(flag) {
expect(flag).to.be.true();
});
});

it('should report isMappedToRole by user.username', function(done) {
ACL.isMappedToRole(ACL.USER, user.username, 'admin', function(err, flag) {
if (err) return done(err);
Expand Down