Skip to content

Commit d57ca42

Browse files
committed
support NotResource/NotAction
1 parent e793a50 commit d57ca42

File tree

4 files changed

+112
-36
lines changed

4 files changed

+112
-36
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
Use the power and flexibility of the AWS IAM Policy syntax in your own application to manage access control. For more details on AWS IAM Policies have a look at https://docs.aws.amazon.com/IAM/latest/UserGuide/policies_overview.html.
88

9-
**Note:** The policy elements `Principal`, `NotPrincipal`, `NotResource` and conditions `ArnEquals`, `ArnNotEquals`, `ArnLike`, `ArnNotLike` are not supported at the moment.
9+
**Note:** The policy elements `Principal`, `NotPrincipal` and conditions `ArnEquals`, `ArnNotEquals`, `ArnLike`, `ArnNotLike` are not supported at the moment.
1010

1111
## Installation
1212

output/intro.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
Use the power and flexibility of the AWS IAM Policy syntax in your own application to manage access control. For more details on AWS IAM Policies have a look at https://docs.aws.amazon.com/IAM/latest/UserGuide/policies_overview.html.
88

9-
**Note:** The policy elements `Principal`, `NotPrincipal`, `NotResource` and conditions `ArnEquals`, `ArnNotEquals`, `ArnLike`, `ArnNotLike` are not supported at the moment.
9+
**Note:** The policy elements `Principal`, `NotPrincipal` and conditions `ArnEquals`, `ArnNotEquals`, `ArnLike`, `ArnNotLike` are not supported at the moment.
1010

1111
## Installation
1212

pbac.js

Lines changed: 20 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@ var _ = require('lodash'),
55
ZSchema = require('z-schema'),
66
util = require('util');
77

8-
9-
108
var PBAC = function constructor(policies, options) {
119
options = _.isPlainObject(options) ? options : {};
1210
var myconditions = _.isPlainObject(options.conditions) ? _.extend(options.conditions, conditions) : conditions;
@@ -18,36 +16,31 @@ var PBAC = function constructor(policies, options) {
1816
conditions: myconditions,
1917
});
2018
this.addConditionsToSchema();
21-
if(this.validateSchema) this._validateSchema();
19+
if (this.validateSchema) this._validateSchema();
2220
this.add(policies);
2321
};
2422

2523
_.extend(PBAC.prototype, {
2624
add: function add(policies) {
2725
policies = _.isArray(policies) ? policies : [policies];
28-
if(this.validatePolicies) this.validate(policies);
26+
if (this.validatePolicies) this.validate(policies);
2927
this.policies.push.apply(this.policies, policies);
3028
},
3129
addConditionsToSchema: function addConditionsToSchema() {
3230
var definition = _.get(this.schema, 'definitions.Condition');
33-
if(!definition) return;
31+
if (!definition) return;
3432
var props = definition.properties = {};
3533
_.forEach(this.conditions, function(condition, name) {
36-
props[name] = { type: 'object' };
34+
props[name] = {
35+
type: 'object'
36+
};
3737
}, this);
3838
},
3939
_validateSchema: function() {
4040
var validator = new ZSchema();
4141
if (!validator.validateSchema(this.schema))
4242
this.throw('schema validation failed with', validator.getLastError());
4343
},
44-
/**
45-
* Validates one or many policies against the schema provided in the constructor.
46-
* Will throw an error if validation fails.
47-
*
48-
* @param {object} policy - Array of policies or single policy object
49-
* @return {boolean} Returns `true` if the policies are valid
50-
*/
5144
validate: function validate(policies) {
5245
policies = _.isArray(policies) ? policies : [policies];
5346
var validator = new ZSchema({
@@ -60,17 +53,6 @@ _.extend(PBAC.prototype, {
6053
return result;
6154
}.bind(this));
6255
},
63-
/**
64-
* Tests an object against the policies and determines if the object passes.
65-
* The method will first try to find a policy with an explicit `Deny` for the combination of
66-
* `resource`, `action` and `condition` (matching policy). If such policy exists, `evaulate` returns false.
67-
* If there is no explicit deny the method will look for a matching policy with an explicit `Allow`.
68-
* `evaulate` will return `true` if such a policy is found. If no matching can be found at all,
69-
* `evaluate` will return `false`.
70-
*
71-
* @param {object} object - Object to test against the policies
72-
* @return {boolean} Returns `true` if the object passes, `false` otherwise
73-
*/
7456
evaluate: function evaluate(options) {
7557
options = _.extend({
7658
action: '',
@@ -96,15 +78,14 @@ _.extend(PBAC.prototype, {
9678
return _(this.policies).pluck('Statement').flatten().find(function(statement, idx) {
9779
if (statement.Effect !== options.effect) return false;
9880
var actionApplies = false;
99-
if (!this.evaluateResource(statement.Resource, options.resource, options.variables))
81+
if (statement.Resource && !this.evaluateResource(statement.Resource, options.resource, options.variables))
82+
return false;
83+
if (statement.NotResource && this.evaluateResource(statement.NotResource, options.resource, options.variables))
84+
return false;
85+
if (statement.Action && !this.evaluateAction(statement.Action, options.action))
86+
return false;
87+
if (statement.NotAction && this.evaluateAction(statement.NotAction, options.action))
10088
return false;
101-
if (statement.Action) actionApplies = _.find(statement.Action, function(action) {
102-
return this.conditions.StringLike(action, options.action);
103-
}.bind(this)) ? true : false;
104-
if (statement.NotAction) actionApplies = _.all(statement.NotAction, function(action) {
105-
return this.conditions.StringNotLike(action, options.action);
106-
}.bind(this));
107-
if (!actionApplies) return false;
10889
return this.evaluateCondition(statement.Condition, options.variables);
10990
}.bind(this));
11091
},
@@ -113,12 +94,17 @@ _.extend(PBAC.prototype, {
11394
return this.getVariableValue(variable, variables);
11495
}.bind(this));
11596
},
116-
getVariableValue: function(variable, variables) {
97+
getVariableValue: function getVariableValue(variable, variables) {
11798
var parts = variable.split(':');
11899
if (_.isPlainObject(variables[parts[0]]) && !_.isUndefined(variables[parts[0]][parts[1]]))
119100
return variables[parts[0]][parts[1]];
120101
else return variable;
121102
},
103+
evaluateAction: function evaluateAction(actions, reference) {
104+
return _.find(actions, function(action) {
105+
return this.conditions.StringLike.call(this, action, reference);
106+
}.bind(this));
107+
},
122108
evaluateResource: function evaluateResource(resources, reference, variables) {
123109
resources = _.isArray(resources) ? resources : [resources];
124110
return _.find(resources, function(resource) {
@@ -139,7 +125,7 @@ _.extend(PBAC.prototype, {
139125
}.bind(this));
140126
}.bind(this));
141127
},
142-
throw: function(name, message) {
128+
throw: function (name, message) {
143129
var args = [].slice.call(arguments, 2);
144130
args.unshift(message);
145131
var e = new Error();

t/notaction.js

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
var assert = require('assert'),
2+
PBAC = require('../pbac');
3+
4+
var tests = [{
5+
name: 'explicit deny overwrites allow',
6+
policies: [{
7+
"Version": "2012-10-17",
8+
"Statement": [{
9+
"Effect": "Deny",
10+
"Action": [
11+
"iam:CreateUser"
12+
],
13+
"Resource": [
14+
"*"
15+
]
16+
}, {
17+
"Effect": "Allow",
18+
"Action": [
19+
"iam:*User"
20+
],
21+
"Resource": [
22+
"abc*"
23+
]
24+
}]
25+
}],
26+
tests: [{
27+
params: {
28+
action: 'iam:CreateUser',
29+
resource: 'abcfoo',
30+
},
31+
result: false,
32+
}, {
33+
params: {
34+
action: 'iam:UpdateUser',
35+
resource: 'abcfoo',
36+
},
37+
result: true,
38+
}, {
39+
params: {
40+
action: 'iam:UpdateUser',
41+
resource: 'foo',
42+
},
43+
result: false,
44+
}]
45+
}, {
46+
name: 'implicit deny with NotAction',
47+
policies: [{
48+
"Version": "2012-10-17",
49+
"Statement": [{
50+
"Effect": "Allow",
51+
"NotAction": [
52+
"iam:CreateUser"
53+
],
54+
"NotResource": [
55+
"abc*"
56+
]
57+
}]
58+
}],
59+
tests: [{
60+
params: {
61+
action: 'iam:CreateUser',
62+
},
63+
result: false,
64+
}, {
65+
params: {
66+
action: 'iam:UpdateUser',
67+
},
68+
result: true,
69+
}, {
70+
params: {
71+
resource: 'abcfoo',
72+
action: 'iam:UpdateUser',
73+
},
74+
result: false,
75+
}]
76+
}];
77+
78+
79+
describe('policies', function() {
80+
tests.forEach(function(test, idx) {
81+
var pbac = new PBAC(test.policies);
82+
it(test.name, function() {
83+
test.tests.forEach(function(params) {
84+
assert.equal(!!pbac.evaluate(params.params), params.result);
85+
});
86+
});
87+
88+
});
89+
90+
});

0 commit comments

Comments
 (0)