Various ACL fixes

This commit is contained in:
Ritchie Martori 2013-12-10 21:49:18 -08:00
parent f08b09823d
commit 4560ec0964
4 changed files with 36 additions and 28 deletions

View File

@ -162,12 +162,7 @@ app.enableAuth = function() {
var req = ctx.req; var req = ctx.req;
var Model = method.ctor; var Model = method.ctor;
var modelInstance = ctx.instance; var modelInstance = ctx.instance;
var modelId = modelInstance && modelInstance.id; var modelId = modelInstance && modelInstance.id || req.param('id');
// TODO(ritch) - this fallback could be less express dependent
if(modelInstance && !modelId) {
modelId = req.param('id');
}
Model.checkAccess( Model.checkAccess(
req.accessToken, req.accessToken,

View File

@ -95,7 +95,7 @@ AccessToken.findForRequest = function(req, options, cb) {
this.findById(id, function(err, token) { this.findById(id, function(err, token) {
if(err) { if(err) {
cb(err); cb(err);
} else { } else if(token) {
token.validate(function(err, isValid) { token.validate(function(err, isValid) {
if(err) { if(err) {
cb(err); cb(err);
@ -105,6 +105,8 @@ AccessToken.findForRequest = function(req, options, cb) {
cb(new Error('Invalid Access Token')); cb(new Error('Invalid Access Token'));
} }
}); });
} else {
cb();
} }
}); });
} else { } else {

View File

@ -34,6 +34,7 @@
var loopback = require('../loopback'); var loopback = require('../loopback');
var async = require('async'); var async = require('async');
var assert = require('assert'); var assert = require('assert');
var debug = require('debug')('acl');
var role = require('./role'); var role = require('./role');
var Role = role.Role; var Role = role.Role;
@ -190,6 +191,7 @@ function resolvePermission(acls, req) {
} }
} }
} }
return { return {
model: req.model, model: req.model,
property: req.property, property: req.property,
@ -208,7 +210,7 @@ function resolvePermission(acls, req) {
* *
* @return {Object[]} An array of ACLs * @return {Object[]} An array of ACLs
*/ */
function getStaticACLs(principalType, principalId, model, property, accessType) { function getStaticACLs(model, property, accessType) {
var modelClass = loopback.getModel(model); var modelClass = loopback.getModel(model);
var staticACLs = []; var staticACLs = [];
if (modelClass && modelClass.settings.acls) { if (modelClass && modelClass.settings.acls) {
@ -269,7 +271,7 @@ ACL.checkPermission = function (principalType, principalId, model, property, acc
accessType: accessType accessType: accessType
}; };
var acls = getStaticACLs(principalType, principalId, model, property, accessType); var acls = getStaticACLs(model, property, accessType);
var resolved = resolvePermission(acls, req); var resolved = resolvePermission(acls, req);
@ -355,21 +357,7 @@ ACL.checkAccess = function (context, callback) {
}; };
var effectiveACLs = []; var effectiveACLs = [];
var staticACLs = getStaticACLs(model.modelName, property, accessType);
// Check the LDL ACLs
principals.forEach(function(p) {
effectiveACLs = effectiveACLs.concat(getStaticACLs(p.principalType, p.principalId, model.modelName, property, accessType));
});
var resolved = resolvePermission(effectiveACLs, req);
if(resolved && resolved.permission === ACL.DENY) {
// Fail fast
process.nextTick(function() {
callback && callback(null, resolved);
});
return;
}
ACL.find({where: {model: model.modelName, property: propertyQuery, accessType: accessTypeQuery}}, function (err, acls) { ACL.find({where: {model: model.modelName, property: propertyQuery, accessType: accessTypeQuery}}, function (err, acls) {
if (err) { if (err) {
@ -377,6 +365,9 @@ ACL.checkAccess = function (context, callback) {
return; return;
} }
var inRoleTasks = []; var inRoleTasks = [];
acls = acls.concat(staticACLs);
acls.forEach(function (acl) { acls.forEach(function (acl) {
principals.forEach(function (principal) { principals.forEach(function (principal) {
if (principal.principalType === acl.pricipalType && principal.principalId === acl.principalId) { if (principal.principalType === acl.pricipalType && principal.principalId === acl.principalId) {
@ -384,11 +375,12 @@ ACL.checkAccess = function (context, callback) {
} else if (acl.principalType === ACL.ROLE) { } else if (acl.principalType === ACL.ROLE) {
inRoleTasks.push(function (done) { inRoleTasks.push(function (done) {
Role.isInRole(acl.principalId, Role.isInRole(acl.principalId,
{principalType: principal.principalType, principalId: acl.principalId, model: model, id: id, property: property}, {principalType: principal.principalType, userId: context.userId, principalId: acl.principalId, model: model, id: id, property: property},
function (err, inRole) { function (err, inRole) {
if(!err) { if(!err && inRole) {
effectiveACLs.push(acl); effectiveACLs.push(acl);
} }
done(err, acl); done(err, acl);
}); });
}); });
@ -429,12 +421,14 @@ ACL.checkAccessForToken = function(token, model, modelId, method, callback) {
var modelCtor = loopback.getModel(model); var modelCtor = loopback.getModel(model);
var context = { var context = {
userId: token.userId,
principals: principals, principals: principals,
model: model, model: model,
property: method, property: method,
accessType: modelCtor._getAccessTypeForMethod(method), accessType: modelCtor._getAccessTypeForMethod(method),
id: modelId id: modelId
}; };
ACL.checkAccess(context, function(err, access) { ACL.checkAccess(context, function(err, access) {
if(err) { if(err) {
callback && callback(err); callback && callback(err);

View File

@ -161,11 +161,28 @@ 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.principalId; var userId = context.userId;
isOwner(modelClass, id, userId, callback); isOwner(modelClass, id, userId, callback);
}); });
function isOwner(modelClass, id, userId, callback) { function isOwner(modelClass, id, userId, callback) {
if(!userId) {
process.nextTick(function() {
callback(null, false);
});
return;
}
var modelClassIsUserClass = modelClass.prototype instanceof loopback.User
|| modelClass === loopback.User;
if(modelClassIsUserClass) {
process.nextTick(function() {
callback(null, id === userId);
});
return;
}
modelClass.findById(id, function(err, inst) { modelClass.findById(id, function(err, inst) {
if(err) { if(err) {
callback && callback(err); callback && callback(err);