Enhance getRoles() to support smart roles
This commit is contained in:
parent
82eeaeee6b
commit
178674ec9a
|
@ -1,5 +1,7 @@
|
|||
var loopback = require('../loopback');
|
||||
var debug = require('debug')('role');
|
||||
var assert = require('assert');
|
||||
var async = require('async');
|
||||
|
||||
// Role model
|
||||
var RoleSchema = {
|
||||
|
@ -167,7 +169,7 @@ Role.registerResolver(Role.OWNER, function(role, context, callback) {
|
|||
var modelClass = context.model;
|
||||
var id = context.id;
|
||||
var userId = context.userId || context.principalId;
|
||||
isOwner(modelClass, id, userId, callback);
|
||||
Role.isOwner(modelClass, id, userId, callback);
|
||||
});
|
||||
|
||||
function isUserClass(modelClass) {
|
||||
|
@ -175,8 +177,16 @@ function isUserClass(modelClass) {
|
|||
modelClass.prototype instanceof loopback.User;
|
||||
}
|
||||
|
||||
function isOwner(modelClass, id, userId, callback) {
|
||||
debug('isOwner(): %s %s %s', modelClass && modelClass.modelName, id, userId);
|
||||
/**
|
||||
* Check if a given userId is the owner the model instance
|
||||
* @param {Function} modelClass The model class
|
||||
* @param {*} modelId The model id
|
||||
* @param {*) userId The user id
|
||||
* @param {Function} callback
|
||||
*/
|
||||
Role.isOwner = function isOwner(modelClass, modelId, userId, callback) {
|
||||
assert(modelClass, 'Model class is required');
|
||||
debug('isOwner(): %s %s %s', modelClass && modelClass.modelName, modelId, userId);
|
||||
// No userId is present
|
||||
if(!userId) {
|
||||
process.nextTick(function() {
|
||||
|
@ -188,12 +198,12 @@ function isOwner(modelClass, id, userId, callback) {
|
|||
// Is the modelClass User or a subclass of User?
|
||||
if(isUserClass(modelClass)) {
|
||||
process.nextTick(function() {
|
||||
callback(null, id === userId);
|
||||
callback(null, modelId === userId);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
modelClass.findById(id, function(err, inst) {
|
||||
modelClass.findById(modelId, function(err, inst) {
|
||||
if(err || !inst) {
|
||||
callback && callback(err, false);
|
||||
return;
|
||||
|
@ -222,7 +232,7 @@ function isOwner(modelClass, id, userId, callback) {
|
|||
callback && callback(null, false);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
Role.registerResolver(Role.AUTHENTICATED, function(role, context, callback) {
|
||||
if(!context) {
|
||||
|
@ -231,15 +241,19 @@ Role.registerResolver(Role.AUTHENTICATED, function(role, context, callback) {
|
|||
});
|
||||
return;
|
||||
}
|
||||
var userId = context.principalId;
|
||||
isAuthenticated(userId, callback);
|
||||
Role.isAuthenticated(context, callback);
|
||||
});
|
||||
|
||||
function isAuthenticated(userId, callback) {
|
||||
/**
|
||||
* Check if the user id is authenticated
|
||||
* @param {Object} context The security context
|
||||
* @param {Function} callback The callback function
|
||||
*/
|
||||
Role.isAuthenticated = function isAuthenticated(context, callback) {
|
||||
process.nextTick(function() {
|
||||
callback && callback(null, !!userId);
|
||||
callback && callback(null, !!context.principalId);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
Role.registerResolver(Role.UNAUTHENTICATED, function(role, context, callback) {
|
||||
process.nextTick(function() {
|
||||
|
@ -304,25 +318,60 @@ Role.isInRole = function (role, context, callback) {
|
|||
|
||||
/**
|
||||
* List roles for a given principal
|
||||
* @param {String} principalType
|
||||
* @param {String|Number} principalId
|
||||
* @param {Object} context The security context
|
||||
* @param {Function} callback
|
||||
*
|
||||
* @callback callback
|
||||
* @param err
|
||||
* @param {String[]} An array of role ids
|
||||
*/
|
||||
Role.getRoles = function (principalType, principalId, callback) {
|
||||
RoleMapping.find({where: {principalType: principalType, principalId: principalId}}, function (err, mappings) {
|
||||
if (err) {
|
||||
callback && callback(err);
|
||||
return;
|
||||
}
|
||||
var roles = [];
|
||||
mappings.forEach(function (m) {
|
||||
roles.push(m.roleId);
|
||||
Role.getRoles = function (context, callback) {
|
||||
debug('getRoles(): %j', context);
|
||||
var roles = [];
|
||||
|
||||
// Check against the smart roles
|
||||
var inRoleTasks = [];
|
||||
Object.keys(Role.resolvers).forEach(function (role) {
|
||||
inRoleTasks.push(function (done) {
|
||||
Role.isInRole(role, context, function (err, inRole) {
|
||||
if (!err && inRole) {
|
||||
if (roles.indexOf(role) === -1) {
|
||||
roles.push(role);
|
||||
}
|
||||
done();
|
||||
} else {
|
||||
done(err, null);
|
||||
}
|
||||
});
|
||||
});
|
||||
callback && callback(null, roles);
|
||||
});
|
||||
|
||||
// Check against the role mappings
|
||||
var principalType = context.principalType || undefined;
|
||||
var principalId = context.principalId || undefined;
|
||||
|
||||
if (principalType && principalId) {
|
||||
// Please find() treat undefined matches all values
|
||||
inRoleTasks.push(function (done) {
|
||||
RoleMapping.find({where: {principalType: principalType,
|
||||
principalId: principalId}}, function (err, mappings) {
|
||||
if (err) {
|
||||
done && done(err);
|
||||
return;
|
||||
}
|
||||
mappings.forEach(function (m) {
|
||||
if (roles.indexOf(m.roleId) === -1) {
|
||||
roles.push(m.roleId);
|
||||
}
|
||||
});
|
||||
done && done();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async.parallel(inRoleTasks, function (err, results) {
|
||||
debug('getRoles() return: %j %j', err, results);
|
||||
callback && callback(err, roles);
|
||||
});
|
||||
};
|
||||
|
||||
|
|
|
@ -85,17 +85,27 @@ describe('role model', function () {
|
|||
assert(!err && exists === false);
|
||||
});
|
||||
|
||||
Role.getRoles(RoleMapping.USER, user.id, function (err, roles) {
|
||||
assert.equal(roles.length, 1);
|
||||
assert.equal(roles[0], role.id);
|
||||
Role.getRoles({principalType: RoleMapping.USER, principalId: user.id}, function (err, roles) {
|
||||
assert.equal(roles.length, 3); // everyone, authenticated, userRole
|
||||
assert(roles.indexOf(role.id) >=0);
|
||||
assert(roles.indexOf(Role.EVERYONE) >=0);
|
||||
assert(roles.indexOf(Role.AUTHENTICATED) >=0);
|
||||
});
|
||||
Role.getRoles(RoleMapping.APP, user.id, function (err, roles) {
|
||||
assert.equal(roles.length, 0);
|
||||
Role.getRoles({principalType: RoleMapping.APP, principalId: user.id}, function (err, roles) {
|
||||
assert.equal(roles.length, 2);
|
||||
assert(roles.indexOf(Role.EVERYONE) >=0);
|
||||
assert(roles.indexOf(Role.AUTHENTICATED) >=0);
|
||||
});
|
||||
Role.getRoles(RoleMapping.USER, 100, function (err, roles) {
|
||||
assert.equal(roles.length, 0);
|
||||
Role.getRoles({principalType: RoleMapping.USER, principalId: 100}, function (err, roles) {
|
||||
assert.equal(roles.length, 2);
|
||||
assert(roles.indexOf(Role.EVERYONE) >=0);
|
||||
assert(roles.indexOf(Role.AUTHENTICATED) >=0);
|
||||
});
|
||||
Role.getRoles({principalType: RoleMapping.USER, principalId: null}, function (err, roles) {
|
||||
assert.equal(roles.length, 2);
|
||||
assert(roles.indexOf(Role.EVERYONE) >=0);
|
||||
assert(roles.indexOf(Role.UNAUTHENTICATED) >=0);
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue