2013-07-01 18:51:28 +00:00
|
|
|
/**
|
2013-11-10 06:22:16 +00:00
|
|
|
Schema ACL options
|
2013-06-26 23:25:51 +00:00
|
|
|
|
2013-11-10 06:22:16 +00:00
|
|
|
Object level permissions, for example, an album owned by a user
|
2013-06-26 23:25:51 +00:00
|
|
|
|
2013-11-10 06:22:16 +00:00
|
|
|
Factors to be authorized against:
|
2013-06-26 23:25:51 +00:00
|
|
|
|
2013-11-10 06:22:16 +00:00
|
|
|
* model name: Album
|
|
|
|
* model instance properties: userId of the album, friends, shared
|
|
|
|
* methods
|
|
|
|
* app and/or user ids/roles
|
2013-07-01 18:51:28 +00:00
|
|
|
** loggedIn
|
|
|
|
** roles
|
|
|
|
** userId
|
|
|
|
** appId
|
|
|
|
** none
|
|
|
|
** everyone
|
|
|
|
** relations: owner/friend/granted
|
2013-06-26 23:25:51 +00:00
|
|
|
|
2013-11-10 06:22:16 +00:00
|
|
|
Class level permissions, for example, Album
|
2013-07-01 18:51:28 +00:00
|
|
|
* model name: Album
|
|
|
|
* methods
|
2013-07-15 21:07:17 +00:00
|
|
|
|
2013-11-10 06:22:16 +00:00
|
|
|
URL/Route level permissions
|
2013-07-18 18:44:25 +00:00
|
|
|
* url pattern
|
|
|
|
* application id
|
|
|
|
* ip addresses
|
|
|
|
* http headers
|
2013-07-15 21:07:17 +00:00
|
|
|
|
2013-11-10 06:22:16 +00:00
|
|
|
Map to oAuth 2.0 scopes
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
var loopback = require('../loopback');
|
2013-11-20 21:31:30 +00:00
|
|
|
var async = require('async');
|
|
|
|
var assert = require('assert');
|
2013-12-11 05:49:18 +00:00
|
|
|
var debug = require('debug')('acl');
|
2013-11-20 21:31:30 +00:00
|
|
|
|
|
|
|
var role = require('./role');
|
|
|
|
var Role = role.Role;
|
2013-11-10 06:22:16 +00:00
|
|
|
|
2013-11-12 06:16:51 +00:00
|
|
|
/**
|
2013-12-11 07:33:57 +00:00
|
|
|
* Schema for Scope which represents the permissions that are granted to client
|
|
|
|
* applications by the resource owner
|
2013-11-12 06:16:51 +00:00
|
|
|
*/
|
2013-11-10 06:22:16 +00:00
|
|
|
var ScopeSchema = {
|
|
|
|
name: {type: String, required: true},
|
|
|
|
description: String
|
2013-11-04 21:19:02 +00:00
|
|
|
};
|
|
|
|
|
2013-11-10 06:22:16 +00:00
|
|
|
|
|
|
|
/**
|
2013-11-12 06:16:51 +00:00
|
|
|
* Resource owner grants/delegates permissions to client applications
|
|
|
|
*
|
2013-12-11 07:33:57 +00:00
|
|
|
* For a protected resource, does the client application have the authorization
|
|
|
|
* from the resource owner (user or system)?
|
2013-11-12 06:16:51 +00:00
|
|
|
*
|
2013-11-10 06:22:16 +00:00
|
|
|
* Scope has many resource access entries
|
|
|
|
* @type {createModel|*}
|
|
|
|
*/
|
2013-11-13 18:02:59 +00:00
|
|
|
var Scope = loopback.createModel('Scope', ScopeSchema);
|
2013-11-10 06:22:16 +00:00
|
|
|
|
2013-11-12 06:16:51 +00:00
|
|
|
/**
|
2013-12-11 07:33:57 +00:00
|
|
|
* System grants permissions to principals (users/applications, can be grouped
|
|
|
|
* into roles).
|
2013-11-12 06:16:51 +00:00
|
|
|
*
|
2013-12-11 07:33:57 +00:00
|
|
|
* Protected resource: the model data and operations
|
|
|
|
* (model/property/method/relation/…)
|
2013-11-12 06:16:51 +00:00
|
|
|
*
|
2013-12-11 07:33:57 +00:00
|
|
|
* For a given principal, such as client application and/or user, is it allowed
|
|
|
|
* to access (read/write/execute)
|
2013-11-12 06:16:51 +00:00
|
|
|
* the protected resource?
|
|
|
|
*
|
|
|
|
*/
|
2013-07-18 18:44:25 +00:00
|
|
|
var ACLSchema = {
|
2013-11-10 06:22:16 +00:00
|
|
|
model: String, // The name of the model
|
|
|
|
property: String, // The name of the property, method, scope, or relation
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Name of the access type - READ/WRITE/EXEC
|
|
|
|
*/
|
|
|
|
accessType: String,
|
|
|
|
|
|
|
|
/**
|
2013-12-11 07:33:57 +00:00
|
|
|
* ALARM - Generate an alarm, in a system dependent way, the access specified
|
|
|
|
* in the permissions component of the ACL entry.
|
2013-11-10 06:22:16 +00:00
|
|
|
* ALLOW - Explicitly grants access to the resource.
|
2013-12-11 07:33:57 +00:00
|
|
|
* AUDIT - Log, in a system dependent way, the access specified in the
|
|
|
|
* permissions component of the ACL entry.
|
2013-11-10 06:22:16 +00:00
|
|
|
* DENY - Explicitly denies access to the resource.
|
|
|
|
*/
|
|
|
|
permission: String,
|
|
|
|
/**
|
|
|
|
* Type of the principal - Application/User/Role
|
|
|
|
*/
|
|
|
|
principalType: String,
|
|
|
|
/**
|
|
|
|
* Id of the principal - such as appId, userId or roleId
|
|
|
|
*/
|
|
|
|
principalId: String
|
2013-10-28 17:44:05 +00:00
|
|
|
};
|
2013-07-18 18:44:25 +00:00
|
|
|
|
2013-11-04 21:19:02 +00:00
|
|
|
var ACL = loopback.createModel('ACL', ACLSchema);
|
|
|
|
|
2013-11-12 18:10:32 +00:00
|
|
|
ACL.ALL = '*';
|
|
|
|
|
2013-12-09 23:26:53 +00:00
|
|
|
ACL.DEFAULT = 'DEFAULT'; // Not specified
|
|
|
|
ACL.ALLOW = 'ALLOW'; // Allow
|
|
|
|
ACL.ALARM = 'ALARM'; // Warn - send an alarm
|
|
|
|
ACL.AUDIT = 'AUDIT'; // Audit - record the access
|
|
|
|
ACL.DENY = 'DENY'; // Deny
|
2013-11-12 18:10:32 +00:00
|
|
|
|
2013-12-09 23:26:53 +00:00
|
|
|
ACL.READ = 'READ'; // Read operation
|
|
|
|
ACL.WRITE = 'WRITE'; // Write operation
|
|
|
|
ACL.EXECUTE = 'EXECUTE'; // Execute operation
|
2013-11-12 18:10:32 +00:00
|
|
|
|
|
|
|
ACL.USER = 'USER';
|
|
|
|
ACL.APP = ACL.APPLICATION = 'APP';
|
|
|
|
ACL.ROLE = 'ROLE';
|
2013-11-13 18:02:59 +00:00
|
|
|
ACL.SCOPE = 'SCOPE';
|
2013-11-12 18:10:32 +00:00
|
|
|
|
|
|
|
var permissionOrder = {
|
2013-11-20 21:31:30 +00:00
|
|
|
DEFAULT: 0,
|
2013-11-12 18:10:32 +00:00
|
|
|
ALLOW: 1,
|
|
|
|
ALARM: 2,
|
|
|
|
AUDIT: 3,
|
|
|
|
DENY: 4
|
2013-11-10 06:22:16 +00:00
|
|
|
};
|
|
|
|
|
2013-12-09 23:26:53 +00:00
|
|
|
/**
|
|
|
|
* Calculate the matching score for the given rule and request
|
|
|
|
* @param {Object} rule The ACL entry
|
|
|
|
* @param {Object} req The request
|
|
|
|
* @returns {number}
|
|
|
|
*/
|
|
|
|
function getMatchingScore(rule, req) {
|
|
|
|
var props = ['model', 'property', 'accessType'];
|
|
|
|
var score = 0;
|
|
|
|
for (var i = 0; i < props.length; i++) {
|
|
|
|
// Shift the score by 4 for each of the properties as the weight
|
|
|
|
score = score * 4;
|
|
|
|
var val1 = rule[props[i]] || ACL.ALL;
|
|
|
|
var val2 = req[props[i]] || ACL.ALL;
|
|
|
|
if (val1 === val2) {
|
|
|
|
// Exact match
|
|
|
|
score += 3;
|
|
|
|
} else if (val1 === ACL.ALL) {
|
|
|
|
// Wildcard match
|
|
|
|
score += 2;
|
|
|
|
} else if (val2 === ACL.ALL) {
|
|
|
|
// Doesn't match at all
|
|
|
|
score += 1;
|
|
|
|
} else {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
score = score * 4;
|
|
|
|
score += permissionOrder[rule.permission || ACL.ALLOW] - 1;
|
|
|
|
return score;
|
2013-11-12 18:10:32 +00:00
|
|
|
}
|
|
|
|
|
2013-11-15 17:41:26 +00:00
|
|
|
/*!
|
|
|
|
* Resolve permission from the ACLs
|
2013-12-09 23:26:53 +00:00
|
|
|
* @param {Object[]) acls The list of ACLs
|
|
|
|
* @param {Object} req The request
|
|
|
|
* @returns {Object} The effective ACL
|
2013-11-15 17:41:26 +00:00
|
|
|
*/
|
2013-12-09 23:26:53 +00:00
|
|
|
function resolvePermission(acls, req) {
|
|
|
|
// Sort by the matching score in descending order
|
|
|
|
acls = acls.sort(function (rule1, rule2) {
|
|
|
|
return getMatchingScore(rule2, req) - getMatchingScore(rule1, req);
|
|
|
|
});
|
|
|
|
var permission = ACL.DEFAULT;
|
|
|
|
var score = 0;
|
|
|
|
for (var i = 0; i < acls.length; i++) {
|
|
|
|
score = getMatchingScore(acls[i], req);
|
|
|
|
if (score < 0) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (req.model !== ACL.ALL &&
|
|
|
|
req.property !== ACL.ALL &&
|
|
|
|
req.accessType !== ACL.ALL) {
|
|
|
|
// We should stop from the first match for non-wildcard
|
|
|
|
permission = acls[i].permission;
|
|
|
|
break;
|
|
|
|
} else {
|
|
|
|
if(acls[i].model === req.model &&
|
|
|
|
acls[i].property === req.property &&
|
|
|
|
acls[i].accessType === req.accessType
|
|
|
|
) {
|
|
|
|
// We should stop at the exact match
|
|
|
|
permission = acls[i].permission;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
// For wildcard match, find the strongest permission
|
|
|
|
if(permissionOrder[acls[i].permission] > permissionOrder[permission]) {
|
|
|
|
permission = acls[i].permission;
|
2013-11-15 17:41:26 +00:00
|
|
|
}
|
|
|
|
}
|
2013-12-09 23:26:53 +00:00
|
|
|
}
|
2013-12-11 05:49:18 +00:00
|
|
|
|
2013-12-09 23:26:53 +00:00
|
|
|
return {
|
|
|
|
model: req.model,
|
|
|
|
property: req.property,
|
|
|
|
accessType: req.accessType,
|
|
|
|
permission: permission || ACL.DEFAULT
|
|
|
|
};
|
2013-11-15 17:41:26 +00:00
|
|
|
}
|
|
|
|
|
2013-11-20 21:31:30 +00:00
|
|
|
/*!
|
2013-12-11 07:33:57 +00:00
|
|
|
* Get the static ACLs from the model definition
|
2013-11-20 21:31:30 +00:00
|
|
|
* @param {String} model The model name
|
|
|
|
* @param {String} property The property/method/relation name
|
|
|
|
*
|
2013-12-09 23:26:53 +00:00
|
|
|
* @return {Object[]} An array of ACLs
|
2013-11-12 06:16:51 +00:00
|
|
|
*/
|
2013-12-11 07:33:57 +00:00
|
|
|
function getStaticACLs(model, property) {
|
2013-11-20 21:31:30 +00:00
|
|
|
var modelClass = loopback.getModel(model);
|
2013-11-15 17:41:26 +00:00
|
|
|
var staticACLs = [];
|
2013-11-20 21:31:30 +00:00
|
|
|
if (modelClass && modelClass.settings.acls) {
|
|
|
|
modelClass.settings.acls.forEach(function (acl) {
|
|
|
|
staticACLs.push({
|
|
|
|
model: model,
|
|
|
|
property: acl.property || ACL.ALL,
|
|
|
|
principalType: acl.principalType,
|
|
|
|
principalId: acl.principalId, // TODO: Should it be a name?
|
|
|
|
accessType: acl.accessType,
|
|
|
|
permission: acl.permission
|
2013-11-15 17:41:26 +00:00
|
|
|
});
|
2013-11-20 21:31:30 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
var prop = modelClass &&
|
|
|
|
(modelClass.definition.properties[property] // regular property
|
2013-11-15 18:08:49 +00:00
|
|
|
|| (modelClass._scopeMeta && modelClass._scopeMeta[property]) // relation/scope
|
|
|
|
|| modelClass[property] // static method
|
|
|
|
|| modelClass.prototype[property]); // prototype method
|
2013-11-20 21:31:30 +00:00
|
|
|
if (prop && prop.acls) {
|
|
|
|
prop.acls.forEach(function (acl) {
|
|
|
|
staticACLs.push({
|
|
|
|
model: modelClass.modelName,
|
|
|
|
property: property,
|
|
|
|
principalType: acl.principalType,
|
|
|
|
principalId: acl.principalId,
|
|
|
|
accessType: acl.accessType,
|
|
|
|
permission: acl.permission
|
2013-11-15 17:41:26 +00:00
|
|
|
});
|
2013-11-20 21:31:30 +00:00
|
|
|
});
|
2013-11-15 17:41:26 +00:00
|
|
|
}
|
|
|
|
|
2013-12-09 23:26:53 +00:00
|
|
|
return staticACLs;
|
2013-11-20 21:31:30 +00:00
|
|
|
}
|
2013-11-15 17:41:26 +00:00
|
|
|
|
2013-11-20 21:31:30 +00:00
|
|
|
/**
|
|
|
|
* Check if the given principal is allowed to access the model/property
|
|
|
|
* @param {String} principalType The principal type
|
|
|
|
* @param {String} principalId The principal id
|
|
|
|
* @param {String} model The model name
|
|
|
|
* @param {String} property The property/method/relation name
|
|
|
|
* @param {String} accessType The access type
|
|
|
|
* @param {Function} callback The callback function
|
|
|
|
*
|
|
|
|
* @callback callback
|
|
|
|
* @param {String|Error} err The error object
|
|
|
|
* @param {Object} the access permission
|
|
|
|
*/
|
|
|
|
ACL.checkPermission = function (principalType, principalId, model, property, accessType, callback) {
|
|
|
|
property = property || ACL.ALL;
|
|
|
|
var propertyQuery = (property === ACL.ALL) ? undefined : {inq: [property, ACL.ALL]};
|
|
|
|
accessType = accessType || ACL.ALL;
|
|
|
|
var accessTypeQuery = (accessType === ACL.ALL) ? undefined : {inq: [accessType, ACL.ALL]};
|
2013-12-09 23:26:53 +00:00
|
|
|
|
|
|
|
var req = {
|
|
|
|
model: model,
|
|
|
|
property: property,
|
|
|
|
accessType: accessType
|
|
|
|
};
|
|
|
|
|
2013-12-11 07:33:57 +00:00
|
|
|
var acls = getStaticACLs(model, property);
|
2013-12-09 23:26:53 +00:00
|
|
|
|
|
|
|
var resolved = resolvePermission(acls, req);
|
|
|
|
|
|
|
|
if(resolved && resolved.permission === ACL.DENY) {
|
2013-11-15 17:41:26 +00:00
|
|
|
// Fail fast
|
2013-11-20 21:31:30 +00:00
|
|
|
process.nextTick(function() {
|
2013-12-09 23:26:53 +00:00
|
|
|
callback && callback(null, resolved);
|
2013-11-20 21:31:30 +00:00
|
|
|
});
|
2013-11-15 17:41:26 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-11-12 06:16:51 +00:00
|
|
|
ACL.find({where: {principalType: principalType, principalId: principalId,
|
2013-11-14 01:14:13 +00:00
|
|
|
model: model, property: propertyQuery, accessType: accessTypeQuery}},
|
2013-12-09 23:26:53 +00:00
|
|
|
function (err, dynACLs) {
|
2013-11-12 06:16:51 +00:00
|
|
|
if (err) {
|
|
|
|
callback && callback(err);
|
|
|
|
return;
|
|
|
|
}
|
2013-12-09 23:26:53 +00:00
|
|
|
acls = acls.concat(dynACLs);
|
|
|
|
resolved = resolvePermission(acls, req);
|
|
|
|
if(resolved && resolved.permission === ACL.DEFAULT) {
|
2013-11-20 21:31:30 +00:00
|
|
|
var modelClass = loopback.getModel(model);
|
2013-12-09 23:26:53 +00:00
|
|
|
resolved.permission = (modelClass && modelClass.settings.defaultPermission) || ACL.ALLOW;
|
2013-11-20 21:31:30 +00:00
|
|
|
}
|
2013-12-09 23:26:53 +00:00
|
|
|
callback && callback(null, resolved);
|
2013-11-12 06:16:51 +00:00
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Check if the given scope is allowed to access the model/property
|
2013-11-20 21:31:30 +00:00
|
|
|
* @param {String} scope The scope name
|
|
|
|
* @param {String} model The model name
|
|
|
|
* @param {String} property The property/method/relation name
|
|
|
|
* @param {String} accessType The access type
|
|
|
|
* @param {Function} callback The callback function
|
|
|
|
*
|
|
|
|
* @callback callback
|
|
|
|
* @param {String|Error} err The error object
|
|
|
|
* @param {Object} the access permission
|
2013-11-12 06:16:51 +00:00
|
|
|
*/
|
|
|
|
Scope.checkPermission = function (scope, model, property, accessType, callback) {
|
2013-11-10 06:22:16 +00:00
|
|
|
Scope.findOne({where: {name: scope}}, function (err, scope) {
|
|
|
|
if (err) {
|
|
|
|
callback && callback(err);
|
|
|
|
} else {
|
2013-11-14 01:14:13 +00:00
|
|
|
ACL.checkPermission(ACL.SCOPE, scope.id, model, property, accessType, callback);
|
2013-11-10 06:22:16 +00:00
|
|
|
}
|
|
|
|
});
|
2013-11-12 18:10:32 +00:00
|
|
|
};
|
|
|
|
|
2013-11-20 21:31:30 +00:00
|
|
|
/**
|
|
|
|
* Check if the request has the permission to access
|
|
|
|
* @param {Object} context
|
2013-12-09 23:26:53 +00:00
|
|
|
* @property {Object[]} principals An array of principals
|
|
|
|
* @property {String|Model} model The model name or model class
|
|
|
|
* @property {*} id The model instance id
|
|
|
|
* @property {String} property The property/method/relation name
|
|
|
|
* @property {String} accessType The access type
|
2013-11-20 21:31:30 +00:00
|
|
|
* @param {Function} callback
|
|
|
|
*/
|
|
|
|
ACL.checkAccess = function (context, callback) {
|
|
|
|
context = context || {};
|
|
|
|
var principals = context.principals || [];
|
2013-11-15 04:19:46 +00:00
|
|
|
|
|
|
|
// add ROLE.EVERYONE
|
|
|
|
principals.unshift({principalType: ACL.ROLE, principalId: Role.EVERYONE});
|
|
|
|
|
2013-11-20 21:31:30 +00:00
|
|
|
var model = context.model;
|
|
|
|
model = ('string' === typeof model) ? loopback.getModel(model) : model;
|
|
|
|
var id = context.id;
|
|
|
|
var property = context.property;
|
|
|
|
var accessType = context.accessType;
|
|
|
|
|
|
|
|
property = property || ACL.ALL;
|
|
|
|
var propertyQuery = (property === ACL.ALL) ? undefined : {inq: [property, ACL.ALL]};
|
|
|
|
accessType = accessType || ACL.ALL;
|
|
|
|
var accessTypeQuery = (accessType === ACL.ALL) ? undefined : {inq: [accessType, ACL.ALL]};
|
|
|
|
|
2013-12-09 23:26:53 +00:00
|
|
|
var req = {
|
|
|
|
model: model.modelName,
|
|
|
|
property: property,
|
|
|
|
accessType: accessType
|
|
|
|
};
|
|
|
|
|
|
|
|
var effectiveACLs = [];
|
2013-12-11 07:33:57 +00:00
|
|
|
var staticACLs = getStaticACLs(model.modelName, property);
|
2013-11-20 21:31:30 +00:00
|
|
|
|
2013-12-11 07:33:57 +00:00
|
|
|
ACL.find({where: {model: model.modelName, property: propertyQuery,
|
|
|
|
accessType: accessTypeQuery}}, function (err, acls) {
|
2013-11-20 21:31:30 +00:00
|
|
|
if (err) {
|
|
|
|
callback && callback(err);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
var inRoleTasks = [];
|
2013-12-11 05:49:18 +00:00
|
|
|
|
|
|
|
acls = acls.concat(staticACLs);
|
|
|
|
|
2013-11-20 21:31:30 +00:00
|
|
|
acls.forEach(function (acl) {
|
|
|
|
principals.forEach(function (principal) {
|
2013-12-11 07:33:57 +00:00
|
|
|
if (principal.principalType === acl.principalType
|
|
|
|
&& String(principal.principalId) === String(acl.principalId)) {
|
2013-11-20 21:31:30 +00:00
|
|
|
effectiveACLs.push(acl);
|
|
|
|
} else if (acl.principalType === ACL.ROLE) {
|
|
|
|
inRoleTasks.push(function (done) {
|
|
|
|
Role.isInRole(acl.principalId,
|
2013-12-11 07:33:57 +00:00
|
|
|
{principalType: principal.principalType,
|
|
|
|
principalId: principal.principalId,
|
|
|
|
userId: context.userId,
|
|
|
|
model: model, id: id, property: property},
|
2013-11-20 21:31:30 +00:00
|
|
|
function (err, inRole) {
|
2013-12-11 05:49:18 +00:00
|
|
|
if(!err && inRole) {
|
2013-11-20 21:31:30 +00:00
|
|
|
effectiveACLs.push(acl);
|
|
|
|
}
|
|
|
|
done(err, acl);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
async.parallel(inRoleTasks, function(err, results) {
|
2013-12-09 23:26:53 +00:00
|
|
|
resolved = resolvePermission(effectiveACLs, req);
|
|
|
|
callback && callback(null, resolved);
|
2013-11-20 21:31:30 +00:00
|
|
|
});
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Check if the given access token can invoke the method
|
|
|
|
* @param {AccessToken} token The access token
|
|
|
|
* @param {String} model The model name
|
|
|
|
* @param {*} modelId The model id
|
|
|
|
* @param {String} method The method name
|
|
|
|
* @param callback The callback function
|
|
|
|
*
|
|
|
|
* @callback callback
|
|
|
|
* @param {String|Error} err The error object
|
|
|
|
* @param {Boolean} allowed is the request allowed
|
|
|
|
*/
|
|
|
|
ACL.checkAccessForToken = function(token, model, modelId, method, callback) {
|
|
|
|
assert(token, 'Access token is required');
|
|
|
|
var principals = [];
|
|
|
|
if(token.userId) {
|
|
|
|
principals.push({principalType: ACL.USER, principalId: token.userId});
|
|
|
|
}
|
|
|
|
if(token.appId) {
|
|
|
|
principals.push({principalType: ACL.APPLICATION, principalId: token.appId});
|
|
|
|
}
|
2013-12-07 01:04:47 +00:00
|
|
|
|
|
|
|
var modelCtor = loopback.getModel(model);
|
|
|
|
|
2013-11-20 21:31:30 +00:00
|
|
|
var context = {
|
2013-12-11 05:49:18 +00:00
|
|
|
userId: token.userId,
|
2013-11-20 21:31:30 +00:00
|
|
|
principals: principals,
|
|
|
|
model: model,
|
|
|
|
property: method,
|
2013-12-07 01:04:47 +00:00
|
|
|
accessType: modelCtor._getAccessTypeForMethod(method),
|
2013-11-20 21:31:30 +00:00
|
|
|
id: modelId
|
|
|
|
};
|
2013-12-11 05:49:18 +00:00
|
|
|
|
2013-11-20 21:31:30 +00:00
|
|
|
ACL.checkAccess(context, function(err, access) {
|
|
|
|
if(err) {
|
|
|
|
callback && callback(err);
|
|
|
|
return;
|
|
|
|
}
|
2013-11-15 04:19:46 +00:00
|
|
|
callback && callback(null, access.permission !== ACL.DENY);
|
2013-11-20 21:31:30 +00:00
|
|
|
});
|
|
|
|
};
|
|
|
|
|
2013-11-12 18:10:32 +00:00
|
|
|
|
|
|
|
module.exports = {
|
|
|
|
ACL: ACL,
|
2013-11-13 18:02:59 +00:00
|
|
|
Scope: Scope
|
2013-11-12 18:10:32 +00:00
|
|
|
};
|