Start to support smart roles such as owner
This commit is contained in:
parent
ada52cf138
commit
2c7c5fc7ec
|
@ -142,21 +142,90 @@ Role.EVERYONE = "$everyone"; // everyone
|
||||||
* @param role
|
* @param role
|
||||||
* @param resolver The resolver function decides if a principal is in the role dynamically
|
* @param resolver The resolver function decides if a principal is in the role dynamically
|
||||||
*
|
*
|
||||||
* isInRole(role, context, callback)
|
* function(role, context, callback)
|
||||||
*/
|
*/
|
||||||
Role.registerResolver = function(role, resolver) {
|
Role.registerResolver = function(role, resolver) {
|
||||||
|
if(!Role.resolvers) {
|
||||||
|
Role.resolvers = {};
|
||||||
|
}
|
||||||
Role.resolvers[role] = resolver;
|
Role.resolvers[role] = resolver;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Role.registerResolver(Role.OWNER, function(role, context, callback) {
|
||||||
|
if(!context || !context.model || !context.id) {
|
||||||
|
process.nextTick(function() {
|
||||||
|
callback && callback(null, false);
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var modelClass = context.model;
|
||||||
|
var id = context.id;
|
||||||
|
var userId = context.principalId;
|
||||||
|
isOwner(modelClass, id, userId, callback);
|
||||||
|
});
|
||||||
|
|
||||||
|
function isOwner(modelClass, id, userId, callback) {
|
||||||
|
modelClass.findById(id, function(err, inst) {
|
||||||
|
if(err) {
|
||||||
|
callback && callback(err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(inst.userId || inst.owner) {
|
||||||
|
callback && callback(null, (inst.userId || inst.owner) === userId);
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
for(var r in modelClass.relations) {
|
||||||
|
var rel = modelClass.relations[r];
|
||||||
|
if(rel.type === 'belongsTo' && rel.model && rel.model.prototype instanceof loopback.User) {
|
||||||
|
callback && callback(null, rel.foreignKey === userId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
callback && callback(null, false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Role.registerResolver(Role.AUTHENTICATED, function(role, context, callback) {
|
||||||
|
if(!context) {
|
||||||
|
process.nextTick(function() {
|
||||||
|
callback && callback(null, false);
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var userId = context.principalId;
|
||||||
|
isAuthenticated(userId, callback);
|
||||||
|
});
|
||||||
|
|
||||||
|
function isAuthenticated(userId, callback) {
|
||||||
|
process.nextTick(function() {
|
||||||
|
callback && callback(null, !!userId);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Role.registerResolver(Role.EVERYONE, function (role, context, callback) {
|
||||||
|
process.nextTick(function () {
|
||||||
|
callback && callback(null, true); // Always true
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if a given principal is in the role
|
* Check if a given principal is in the role
|
||||||
*
|
*
|
||||||
* @param role
|
* @param {String} role The role name
|
||||||
* @param principalType
|
* @param {Object} context The context object
|
||||||
* @param principalId
|
* @param {Function} callback
|
||||||
* @param callback
|
|
||||||
*/
|
*/
|
||||||
Role.isInRole = function (role, principalType, principalId, callback) {
|
Role.isInRole = function (role, context, callback) {
|
||||||
|
var resolver = Role.resolvers[role];
|
||||||
|
if(resolver) {
|
||||||
|
resolver(role, context, callback);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var principalType = context.principalType;
|
||||||
|
var principalId = context.principalId;
|
||||||
|
|
||||||
Role.findOne({where: {name: role}}, function (err, result) {
|
Role.findOne({where: {name: role}}, function (err, result) {
|
||||||
if (err) {
|
if (err) {
|
||||||
callback && callback(err);
|
callback && callback(err);
|
||||||
|
|
|
@ -4,6 +4,7 @@ var role = require('../lib/models/role');
|
||||||
var Role = role.Role;
|
var Role = role.Role;
|
||||||
var RoleMapping = role.RoleMapping;
|
var RoleMapping = role.RoleMapping;
|
||||||
var User = loopback.User;
|
var User = loopback.User;
|
||||||
|
var ACL = require('../lib/models/acl');
|
||||||
|
|
||||||
function checkResult(err, result) {
|
function checkResult(err, result) {
|
||||||
// console.log(err, result);
|
// console.log(err, result);
|
||||||
|
@ -41,19 +42,19 @@ describe('role model', function () {
|
||||||
// console.log('User: ', user.id);
|
// console.log('User: ', user.id);
|
||||||
Role.create({name: 'userRole'}, function (err, role) {
|
Role.create({name: 'userRole'}, function (err, role) {
|
||||||
role.principals.create({principalType: RoleMapping.USER, principalId: user.id}, function (err, p) {
|
role.principals.create({principalType: RoleMapping.USER, principalId: user.id}, function (err, p) {
|
||||||
Role.find(function(err, roles) {
|
Role.find(function (err, roles) {
|
||||||
assert(!err);
|
assert(!err);
|
||||||
assert.equal(roles.length, 1);
|
assert.equal(roles.length, 1);
|
||||||
assert.equal(roles[0].name, 'userRole');
|
assert.equal(roles[0].name, 'userRole');
|
||||||
});
|
});
|
||||||
role.principals(function(err, principals) {
|
role.principals(function (err, principals) {
|
||||||
assert(!err);
|
assert(!err);
|
||||||
// console.log(principals);
|
// console.log(principals);
|
||||||
assert.equal(principals.length, 1);
|
assert.equal(principals.length, 1);
|
||||||
assert.equal(principals[0].principalType, RoleMapping.USER);
|
assert.equal(principals[0].principalType, RoleMapping.USER);
|
||||||
assert.equal(principals[0].principalId, user.id);
|
assert.equal(principals[0].principalId, user.id);
|
||||||
});
|
});
|
||||||
role.users(function(err, users) {
|
role.users(function (err, users) {
|
||||||
assert(!err);
|
assert(!err);
|
||||||
assert.equal(users.length, 1);
|
assert.equal(users.length, 1);
|
||||||
assert.equal(users[0].principalType, RoleMapping.USER);
|
assert.equal(users[0].principalType, RoleMapping.USER);
|
||||||
|
@ -72,26 +73,26 @@ describe('role model', function () {
|
||||||
role.principals.create({principalType: RoleMapping.USER, principalId: user.id}, function (err, p) {
|
role.principals.create({principalType: RoleMapping.USER, principalId: user.id}, function (err, p) {
|
||||||
// Role.find(console.log);
|
// Role.find(console.log);
|
||||||
// role.principals(console.log);
|
// role.principals(console.log);
|
||||||
Role.isInRole('userRole', RoleMapping.USER, user.id, function(err, exists) {
|
Role.isInRole('userRole', {principalType: RoleMapping.USER, principalId: user.id}, function (err, exists) {
|
||||||
assert(!err && exists === true);
|
assert(!err && exists === true);
|
||||||
});
|
});
|
||||||
|
|
||||||
Role.isInRole('userRole', RoleMapping.APP, user.id, function(err, exists) {
|
Role.isInRole('userRole', {principalType: RoleMapping.APP, principalId: user.id}, function (err, exists) {
|
||||||
assert(!err && exists === false);
|
assert(!err && exists === false);
|
||||||
});
|
});
|
||||||
|
|
||||||
Role.isInRole('userRole', RoleMapping.USER, 100, function(err, exists) {
|
Role.isInRole('userRole', {principalType: RoleMapping.USER, principalId: 100}, function (err, exists) {
|
||||||
assert(!err && exists === false);
|
assert(!err && exists === false);
|
||||||
});
|
});
|
||||||
|
|
||||||
Role.getRoles(RoleMapping.USER, user.id, function(err, roles) {
|
Role.getRoles(RoleMapping.USER, user.id, function (err, roles) {
|
||||||
assert.equal(roles.length, 1);
|
assert.equal(roles.length, 1);
|
||||||
assert.equal(roles[0], role.id);
|
assert.equal(roles[0], role.id);
|
||||||
});
|
});
|
||||||
Role.getRoles(RoleMapping.APP, user.id, function(err, roles) {
|
Role.getRoles(RoleMapping.APP, user.id, function (err, roles) {
|
||||||
assert.equal(roles.length, 0);
|
assert.equal(roles.length, 0);
|
||||||
});
|
});
|
||||||
Role.getRoles(RoleMapping.USER, 100, function(err, roles) {
|
Role.getRoles(RoleMapping.USER, 100, function (err, roles) {
|
||||||
assert.equal(roles.length, 0);
|
assert.equal(roles.length, 0);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -101,6 +102,56 @@ describe('role model', function () {
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("should support owner role resolver", function () {
|
||||||
|
var ds = loopback.createDataSource({connector: 'memory'});
|
||||||
|
User.attachTo(ds);
|
||||||
|
Role.attachTo(ds);
|
||||||
|
RoleMapping.attachTo(ds);
|
||||||
|
|
||||||
|
var Album = ds.createModel('Album', {
|
||||||
|
name: String,
|
||||||
|
userId: Number
|
||||||
|
}, {
|
||||||
|
relations: {
|
||||||
|
user: {
|
||||||
|
type: 'belongsTo',
|
||||||
|
model: 'User',
|
||||||
|
foreignKey: 'userId'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
User.create({name: 'Raymond', email: 'x@y.com', password: 'foobar'}, function (err, user) {
|
||||||
|
Role.isInRole(Role.AUTHENTICATED, {principalType: ACL.USER, principalId: user.id}, function (err, yes) {
|
||||||
|
assert(!err && yes);
|
||||||
|
});
|
||||||
|
Role.isInRole(Role.AUTHENTICATED, {principalType: ACL.USER, principalId: null}, function (err, yes) {
|
||||||
|
assert(!err && !yes);
|
||||||
|
});
|
||||||
|
|
||||||
|
Role.isInRole(Role.EVERYONE, {principalType: ACL.USER, principalId: user.id}, function (err, yes) {
|
||||||
|
assert(!err && yes);
|
||||||
|
});
|
||||||
|
|
||||||
|
Role.isInRole(Role.EVERYONE, {principalType: ACL.USER, principalId: null}, function (err, yes) {
|
||||||
|
assert(!err && yes);
|
||||||
|
});
|
||||||
|
|
||||||
|
// console.log('User: ', user.id);
|
||||||
|
Album.create({name: 'Album 1', userId: user.id}, function (err, album1) {
|
||||||
|
Role.isInRole(Role.OWNER, {principalType: ACL.USER, principalId: user.id, model: Album, id: album1.id}, function (err, yes) {
|
||||||
|
assert(!err && yes);
|
||||||
|
});
|
||||||
|
Album.create({name: 'Album 2'}, function (err, album2) {
|
||||||
|
Role.isInRole(Role.OWNER, {principalType: ACL.USER, principalId: user.id, model: Album, id: album2.id}, function (err, yes) {
|
||||||
|
assert(!err && !yes);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue