Enhance getRoles() to support smart roles
This commit is contained in:
parent
82eeaeee6b
commit
178674ec9a
|
@ -1,5 +1,7 @@
|
||||||
var loopback = require('../loopback');
|
var loopback = require('../loopback');
|
||||||
var debug = require('debug')('role');
|
var debug = require('debug')('role');
|
||||||
|
var assert = require('assert');
|
||||||
|
var async = require('async');
|
||||||
|
|
||||||
// Role model
|
// Role model
|
||||||
var RoleSchema = {
|
var RoleSchema = {
|
||||||
|
@ -167,7 +169,7 @@ Role.registerResolver(Role.OWNER, function(role, context, callback) {
|
||||||
var modelClass = context.model;
|
var modelClass = context.model;
|
||||||
var id = context.id;
|
var id = context.id;
|
||||||
var userId = context.userId || context.principalId;
|
var userId = context.userId || context.principalId;
|
||||||
isOwner(modelClass, id, userId, callback);
|
Role.isOwner(modelClass, id, userId, callback);
|
||||||
});
|
});
|
||||||
|
|
||||||
function isUserClass(modelClass) {
|
function isUserClass(modelClass) {
|
||||||
|
@ -175,8 +177,16 @@ function isUserClass(modelClass) {
|
||||||
modelClass.prototype instanceof loopback.User;
|
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
|
// No userId is present
|
||||||
if(!userId) {
|
if(!userId) {
|
||||||
process.nextTick(function() {
|
process.nextTick(function() {
|
||||||
|
@ -188,12 +198,12 @@ function isOwner(modelClass, id, userId, callback) {
|
||||||
// Is the modelClass User or a subclass of User?
|
// Is the modelClass User or a subclass of User?
|
||||||
if(isUserClass(modelClass)) {
|
if(isUserClass(modelClass)) {
|
||||||
process.nextTick(function() {
|
process.nextTick(function() {
|
||||||
callback(null, id === userId);
|
callback(null, modelId === userId);
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
modelClass.findById(id, function(err, inst) {
|
modelClass.findById(modelId, function(err, inst) {
|
||||||
if(err || !inst) {
|
if(err || !inst) {
|
||||||
callback && callback(err, false);
|
callback && callback(err, false);
|
||||||
return;
|
return;
|
||||||
|
@ -222,7 +232,7 @@ function isOwner(modelClass, id, userId, callback) {
|
||||||
callback && callback(null, false);
|
callback && callback(null, false);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
Role.registerResolver(Role.AUTHENTICATED, function(role, context, callback) {
|
Role.registerResolver(Role.AUTHENTICATED, function(role, context, callback) {
|
||||||
if(!context) {
|
if(!context) {
|
||||||
|
@ -231,15 +241,19 @@ Role.registerResolver(Role.AUTHENTICATED, function(role, context, callback) {
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var userId = context.principalId;
|
Role.isAuthenticated(context, callback);
|
||||||
isAuthenticated(userId, 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() {
|
process.nextTick(function() {
|
||||||
callback && callback(null, !!userId);
|
callback && callback(null, !!context.principalId);
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
Role.registerResolver(Role.UNAUTHENTICATED, function(role, context, callback) {
|
Role.registerResolver(Role.UNAUTHENTICATED, function(role, context, callback) {
|
||||||
process.nextTick(function() {
|
process.nextTick(function() {
|
||||||
|
@ -304,25 +318,60 @@ Role.isInRole = function (role, context, callback) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* List roles for a given principal
|
* List roles for a given principal
|
||||||
* @param {String} principalType
|
* @param {Object} context The security context
|
||||||
* @param {String|Number} principalId
|
|
||||||
* @param {Function} callback
|
* @param {Function} callback
|
||||||
*
|
*
|
||||||
* @callback callback
|
* @callback callback
|
||||||
* @param err
|
* @param err
|
||||||
* @param {String[]} An array of role ids
|
* @param {String[]} An array of role ids
|
||||||
*/
|
*/
|
||||||
Role.getRoles = function (principalType, principalId, callback) {
|
Role.getRoles = function (context, callback) {
|
||||||
RoleMapping.find({where: {principalType: principalType, principalId: principalId}}, function (err, mappings) {
|
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);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// 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) {
|
if (err) {
|
||||||
callback && callback(err);
|
done && done(err);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var roles = [];
|
|
||||||
mappings.forEach(function (m) {
|
mappings.forEach(function (m) {
|
||||||
|
if (roles.indexOf(m.roleId) === -1) {
|
||||||
roles.push(m.roleId);
|
roles.push(m.roleId);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
callback && callback(null, roles);
|
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);
|
assert(!err && exists === false);
|
||||||
});
|
});
|
||||||
|
|
||||||
Role.getRoles(RoleMapping.USER, user.id, function (err, roles) {
|
Role.getRoles({principalType: RoleMapping.USER, principalId: user.id}, function (err, roles) {
|
||||||
assert.equal(roles.length, 1);
|
assert.equal(roles.length, 3); // everyone, authenticated, userRole
|
||||||
assert.equal(roles[0], role.id);
|
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) {
|
Role.getRoles({principalType: RoleMapping.APP, principalId: user.id}, function (err, roles) {
|
||||||
assert.equal(roles.length, 0);
|
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) {
|
Role.getRoles({principalType: RoleMapping.USER, principalId: 100}, function (err, roles) {
|
||||||
assert.equal(roles.length, 0);
|
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