!fixup only set ctx.accessType when sharedMethod is available
This commit is contained in:
parent
a2f931ed3f
commit
fea1cee1c4
|
@ -44,7 +44,10 @@ function AccessContext(context) {
|
|||
this.methodNames = [];
|
||||
}
|
||||
|
||||
this.accessType = this.model._getAccessTypeForMethod(this.method);
|
||||
if(this.sharedMethod) {
|
||||
this.accessType = this.model._getAccessTypeForMethod(this.sharedMethod);
|
||||
}
|
||||
|
||||
this.accessType = context.accessType || AccessContext.ALL;
|
||||
this.accessToken = context.accessToken || AccessToken.ANONYMOUS;
|
||||
|
||||
|
@ -240,8 +243,9 @@ function AccessRequest(model, property, accessType, permission, methodNames) {
|
|||
}
|
||||
|
||||
/**
|
||||
* Is the request a wildcard
|
||||
* @returns {boolean}
|
||||
* Does the request contain any wildcards?
|
||||
*
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
AccessRequest.prototype.isWildcard = function () {
|
||||
return this.model === AccessContext.ALL ||
|
||||
|
@ -259,12 +263,7 @@ AccessRequest.prototype.exactlyMatches = function(acl) {
|
|||
var matchesModel = acl.model === this.model;
|
||||
var matchesProperty = acl.property === this.property;
|
||||
var matchesMethodName = this.methodNames.indexOf(acl.property) !== -1;
|
||||
var matchesAccessType = (acl.accessType || '*') === this.accessType;
|
||||
|
||||
debug('matchesModel %s === %s %j', acl.model, this.model, acl.model === this.model);
|
||||
debug('matchesProperty %s === %s %j', acl.property, this.property, acl.property === this.property);
|
||||
debug('matchesMethodName %s in %j %j', acl.property, this.methodNames, this.methodNames.indexOf(acl.property) !== -1);
|
||||
debug('matchesAccessType %s === %s %j', acl.accessType, this.accessType, acl.accessType === this.accessType);
|
||||
var matchesAccessType = acl.accessType === this.accessType;
|
||||
|
||||
if(matchesModel && matchesAccessType) {
|
||||
return matchesProperty || matchesMethodName;
|
||||
|
|
|
@ -125,12 +125,9 @@ ACL.getMatchingScore = function getMatchingScore(rule, req) {
|
|||
score = score * 4;
|
||||
var val1 = rule[props[i]] || ACL.ALL;
|
||||
var val2 = req[props[i]] || ACL.ALL;
|
||||
var isMatchingMethodName = props[i] === 'property' && req.methodNames.indexOf(val1) !== -1;
|
||||
|
||||
if(props[i] === 'property' && req.methodNames.indexOf(val1) !== -1) {
|
||||
score += 3;
|
||||
}
|
||||
|
||||
if (val1 === val2) {
|
||||
if (val1 === val2 || isMatchingMethodName) {
|
||||
// Exact match
|
||||
score += 3;
|
||||
} else if (val1 === ACL.ALL) {
|
||||
|
@ -192,6 +189,16 @@ ACL.getMatchingScore = function getMatchingScore(rule, req) {
|
|||
return score;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get matching score for the given `AccessRequest`.
|
||||
* @param {AccessRequest} req The request
|
||||
* @returns {Number} score
|
||||
*/
|
||||
|
||||
ACL.prototype.score = function(req) {
|
||||
return this.constructor.getMatchingScore(this, req);
|
||||
}
|
||||
|
||||
/*!
|
||||
* Resolve permission from the ACLs
|
||||
* @param {Object[]) acls The list of ACLs
|
||||
|
@ -208,47 +215,35 @@ ACL.resolvePermission = function resolvePermission(acls, req) {
|
|||
});
|
||||
var permission = ACL.DEFAULT;
|
||||
var score = 0;
|
||||
var matchingACL;
|
||||
|
||||
for (var i = 0; i < acls.length; i++) {
|
||||
score = ACL.getMatchingScore(acls[i], req);
|
||||
if (score < 0) {
|
||||
// the highest scored ACL did not match
|
||||
break;
|
||||
}
|
||||
if (!req.isWildcard()) {
|
||||
// We should stop from the first match for non-wildcard
|
||||
debug('Found first match (non-wildcard):');
|
||||
matchingACL = acls[i];
|
||||
permission = matchingACL.permission;
|
||||
permission = acls[i].permission;
|
||||
break;
|
||||
} else {
|
||||
if(req.exactlyMatches(acls[i])) {
|
||||
debug('Exact ACL match:');
|
||||
acls[i].debug();
|
||||
// We should stop at the exact match
|
||||
matchingACL = acls[i];
|
||||
permission = matchingACL.permission;
|
||||
permission = acls[i].permission;
|
||||
break;
|
||||
}
|
||||
// For wildcard match, find the strongest permission
|
||||
if(AccessContext.permissionOrder[acls[i].permission]
|
||||
> AccessContext.permissionOrder[permission]) {
|
||||
matchingACL = acls[i];
|
||||
permission = matchingACL.permission;
|
||||
permission = acls[i].permission;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(debug.enabled) {
|
||||
if(matchingACL) {
|
||||
debug('Matching ACL:');
|
||||
matchingACL.debug();
|
||||
} else {
|
||||
debug('No matching ACL found!')
|
||||
}
|
||||
debug('The following ACLs were searched: ');
|
||||
acls.forEach(function(acl) {
|
||||
acl.debug();
|
||||
debug('with score:', acl.score(req));
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -274,7 +269,7 @@ ACL.getStaticACLs = function getStaticACLs(model, property) {
|
|||
property: acl.property || ACL.ALL,
|
||||
principalType: acl.principalType,
|
||||
principalId: acl.principalId, // TODO: Should it be a name?
|
||||
accessType: acl.accessType,
|
||||
accessType: acl.accessType || ACL.ALL,
|
||||
permission: acl.permission
|
||||
}));
|
||||
});
|
||||
|
@ -393,7 +388,7 @@ ACL.checkAccessForContext = function (context, callback) {
|
|||
var propertyQuery = (property === ACL.ALL) ? undefined : {inq: methodNames.concat([ACL.ALL])};
|
||||
var accessTypeQuery = (accessType === ACL.ALL) ? undefined : {inq: [accessType, ACL.ALL]};
|
||||
|
||||
var req = new AccessRequest(modelName, property, accessType, methodNames);
|
||||
var req = new AccessRequest(modelName, property, accessType, ACL.DEFAULT, methodNames);
|
||||
|
||||
var effectiveACLs = [];
|
||||
var staticACLs = this.getStaticACLs(model.modelName, property);
|
||||
|
|
|
@ -155,7 +155,8 @@ Model.checkAccess = function(token, modelId, sharedMethod, callback) {
|
|||
property: sharedMethod.name,
|
||||
method: sharedMethod.name,
|
||||
sharedMethod: sharedMethod,
|
||||
modelId: modelId
|
||||
modelId: modelId,
|
||||
accessType: this._getAccessTypeForMethod(sharedMethod)
|
||||
}, function(err, accessRequest) {
|
||||
if(err) return callback(err);
|
||||
callback(null, accessRequest.isAllowed());
|
||||
|
@ -172,7 +173,7 @@ Model.checkAccess = function(token, modelId, sharedMethod, callback) {
|
|||
Model._getAccessTypeForMethod = function(method) {
|
||||
if(typeof method === 'string') {
|
||||
method = {name: method};
|
||||
}40
|
||||
}
|
||||
assert(
|
||||
typeof method === 'object',
|
||||
'method is a required argument and must be a RemoteMethod object'
|
||||
|
|
|
@ -319,13 +319,13 @@ Role.registerResolver(Role.EVERYONE, function (role, context, callback) {
|
|||
* @param {Boolean} isInRole
|
||||
*/
|
||||
Role.isInRole = function (role, context, callback) {
|
||||
debug('isInRole(): %s', role);
|
||||
context.debug();
|
||||
|
||||
if (!(context instanceof AccessContext)) {
|
||||
context = new AccessContext(context);
|
||||
}
|
||||
|
||||
debug('isInRole(): %s', role);
|
||||
context.debug();
|
||||
|
||||
var resolver = Role.resolvers[role];
|
||||
if (resolver) {
|
||||
debug('Custom resolver found for role %s', role);
|
||||
|
|
|
@ -101,11 +101,15 @@ describe('security ACLs', function () {
|
|||
property: 'find',
|
||||
accessType: 'WRITE'
|
||||
};
|
||||
|
||||
acls = acls.map(function(a) { return new ACL(a)});
|
||||
|
||||
var perm = ACL.resolvePermission(acls, req);
|
||||
assert.deepEqual(perm, { model: 'account',
|
||||
property: 'find',
|
||||
accessType: 'WRITE',
|
||||
permission: 'ALLOW' });
|
||||
permission: 'ALLOW',
|
||||
methodNames: []});
|
||||
});
|
||||
|
||||
it("should allow access to models for the given principal by wildcard", function () {
|
||||
|
|
Loading…
Reference in New Issue