Add promise support to built-in model ACL
This commit is contained in:
parent
c7e0a15a44
commit
a63fad402e
|
@ -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');
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -340,9 +342,9 @@ 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;
|
||||
|
@ -350,8 +352,7 @@ module.exports = function(ACL) {
|
|||
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);
|
||||
|
@ -359,8 +360,9 @@ module.exports = function(ACL) {
|
|||
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() {
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -452,10 +452,7 @@ 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) {
|
||||
|
@ -463,9 +460,10 @@ module.exports = function(ACL) {
|
|||
}
|
||||
debug('---Resolved---');
|
||||
resolved.debug();
|
||||
if (callback) callback(null, resolved);
|
||||
return callback(null, resolved);
|
||||
});
|
||||
});
|
||||
return callback.promise;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -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,
|
||||
|
@ -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() {
|
||||
|
@ -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) {
|
||||
|
@ -536,6 +533,7 @@ module.exports = function(ACL) {
|
|||
cb(err);
|
||||
});
|
||||
}
|
||||
return cb.promise;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -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) {
|
||||
|
@ -568,5 +567,6 @@ module.exports = function(ACL) {
|
|||
});
|
||||
});
|
||||
});
|
||||
return cb.promise;
|
||||
};
|
||||
};
|
||||
|
|
|
@ -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 = [
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue