Compare commits

...

2 Commits

Author SHA1 Message Date
Will Toozs 227b869869
ARSN-362: add implicit deny logic to policy eval tests 2023-08-25 10:30:04 +02:00
Will Toozs ca00292dd9
ARSN-362: add implicit deny logic to policy evaluation 2023-08-25 10:29:54 +02:00
2 changed files with 193 additions and 3 deletions

View File

@ -310,6 +310,7 @@ export function evaluatePolicy(
} }
/** /**
* @deprecated Upgrade to evaluateAllPoliciesV2
* Evaluate whether a request is permitted under a policy. * Evaluate whether a request is permitted under a policy.
* @param requestContext - Info necessary to * @param requestContext - Info necessary to
* evaluate permission * evaluate permission
@ -325,6 +326,16 @@ export function evaluateAllPolicies(
allPolicies: any[], allPolicies: any[],
log: Logger, log: Logger,
): string { ): string {
return evaluateAllPoliciesV2(requestContext, allPolicies, log).verdict;
}
export function evaluateAllPoliciesV2(
requestContext: RequestContext,
allPolicies: any[],
log: Logger,
): {
verdict: string;
isImplicit: boolean;
} {
log.trace('evaluating all policies'); log.trace('evaluating all policies');
let allow = false; let allow = false;
let allowWithTagCondition = false; let allowWithTagCondition = false;
@ -333,7 +344,10 @@ export function evaluateAllPolicies(
const singlePolicyVerdict = evaluatePolicy(requestContext, allPolicies[i], log); const singlePolicyVerdict = evaluatePolicy(requestContext, allPolicies[i], log);
// If there is any Deny, just return Deny // If there is any Deny, just return Deny
if (singlePolicyVerdict === 'Deny') { if (singlePolicyVerdict === 'Deny') {
return 'Deny'; return {
verdict: 'Deny',
isImplicit: false,
};
} }
if (singlePolicyVerdict === 'Allow') { if (singlePolicyVerdict === 'Allow') {
allow = true; allow = true;
@ -344,6 +358,7 @@ export function evaluateAllPolicies(
} // else 'Neutral' } // else 'Neutral'
} }
let verdict; let verdict;
let isImplicit = false;
if (allow) { if (allow) {
if (denyWithTagCondition) { if (denyWithTagCondition) {
verdict = 'NeedTagConditionEval'; verdict = 'NeedTagConditionEval';
@ -355,8 +370,9 @@ export function evaluateAllPolicies(
verdict = 'NeedTagConditionEval'; verdict = 'NeedTagConditionEval';
} else { } else {
verdict = 'Deny'; verdict = 'Deny';
isImplicit = true;
} }
} }
log.trace('result of evaluating all policies', { verdict }); log.trace('result of evaluating all policies', { verdict, isImplicit });
return verdict; return { verdict, isImplicit };
} }

View File

@ -6,6 +6,7 @@ const fakeTimers = require('@sinonjs/fake-timers');
const evaluator = require('../../lib/policyEvaluator/evaluator'); const evaluator = require('../../lib/policyEvaluator/evaluator');
const evaluatePolicy = evaluator.evaluatePolicy; const evaluatePolicy = evaluator.evaluatePolicy;
const evaluateAllPolicies = evaluator.evaluateAllPolicies; const evaluateAllPolicies = evaluator.evaluateAllPolicies;
const evaluateAllPoliciesV2 = evaluator.evaluateAllPoliciesV2;
const handleWildcards = const handleWildcards =
require('../../lib/policyEvaluator/utils/wildcards').handleWildcards; require('../../lib/policyEvaluator/utils/wildcards').handleWildcards;
const substituteVariables = const substituteVariables =
@ -1451,6 +1452,49 @@ describe('policyEvaluator', () => {
assert.strictEqual(result, 'Deny'); assert.strictEqual(result, 'Deny');
}); });
it('should deny access if any policy results in a Deny', () => {
requestContext = new RequestContext({}, {},
'my_favorite_bucket', undefined,
undefined, undefined, 'bucketDelete', 's3');
requestContext.setRequesterInfo({});
const result = evaluateAllPoliciesV2(requestContext,
[samples['arn:aws:iam::aws:policy/AmazonS3FullAccess'],
samples['Deny Bucket Policy']], log);
assert.deepStrictEqual(result, {
verdict: 'Deny',
isImplicit: false,
});
});
it('should deny access if request action is not in any policy', () => {
requestContext = new RequestContext({}, {},
'notVeryPrivate', undefined,
undefined, undefined, 'bucketDelete', 's3');
requestContext.setRequesterInfo({});
const result = evaluateAllPoliciesV2(requestContext,
[samples['Multi-Statement Policy'],
samples['Variable Bucket Policy']], log);
assert.deepStrictEqual(result, {
verdict: 'Deny',
isImplicit: true,
});
});
it('should deny access if request resource is not in any policy', () => {
requestContext = new RequestContext({}, {},
'notbucket', undefined,
undefined, undefined, 'objectGet', 's3');
requestContext.setRequesterInfo({});
const result = evaluateAllPoliciesV2(requestContext, [
samples['Multi-Statement Policy'],
samples['Variable Bucket Policy'],
], log);
assert.deepStrictEqual(result, {
verdict: 'Deny',
isImplicit: true,
});
});
const TestMatrixPolicies = { const TestMatrixPolicies = {
Allow: { Allow: {
Version: '2012-10-17', Version: '2012-10-17',
@ -1504,6 +1548,136 @@ describe('policyEvaluator', () => {
}, },
}; };
const TestMatrixV2 = [
{
policiesToEvaluate: [],
expectedPolicyEvaluation: {
verdict: 'Deny',
isImplicit: true,
},
},
{
policiesToEvaluate: ['Allow'],
expectedPolicyEvaluation: {
verdict: 'Allow',
isImplicit: false,
},
},
{
policiesToEvaluate: ['Neutral'],
expectedPolicyEvaluation: {
verdict: 'Deny',
isImplicit: true,
},
},
{
policiesToEvaluate: ['Deny'],
expectedPolicyEvaluation: {
verdict: 'Deny',
isImplicit: false,
},
},
{
policiesToEvaluate: ['Allow', 'Allow'],
expectedPolicyEvaluation: {
verdict: 'Allow',
isImplicit: false,
},
},
{
policiesToEvaluate: ['Allow', 'Neutral'],
expectedPolicyEvaluation: {
verdict: 'Allow',
isImplicit: false,
},
},
{
policiesToEvaluate: ['Neutral', 'Allow'],
expectedPolicyEvaluation: {
verdict: 'Allow',
isImplicit: false,
},
},
{
policiesToEvaluate: ['Neutral', 'Neutral'],
expectedPolicyEvaluation: {
verdict: 'Deny',
isImplicit: true,
},
},
{
policiesToEvaluate: ['Allow', 'Deny'],
expectedPolicyEvaluation: {
verdict: 'Deny',
isImplicit: false,
},
},
{
policiesToEvaluate: ['AllowWithTagCondition'],
expectedPolicyEvaluation: {
verdict: 'NeedTagConditionEval',
isImplicit: false,
},
},
{
policiesToEvaluate: ['Allow', 'AllowWithTagCondition'],
expectedPolicyEvaluation: {
verdict: 'Allow',
isImplicit: false,
},
},
{
policiesToEvaluate: ['DenyWithTagCondition'],
expectedPolicyEvaluation: {
verdict: 'Deny',
isImplicit: true,
},
},
{
policiesToEvaluate: ['Allow', 'DenyWithTagCondition'],
expectedPolicyEvaluation: {
verdict: 'NeedTagConditionEval',
isImplicit: false,
},
},
{
policiesToEvaluate: ['AllowWithTagCondition', 'DenyWithTagCondition'],
expectedPolicyEvaluation: {
verdict: 'NeedTagConditionEval',
isImplicit: false,
},
},
{
policiesToEvaluate: ['AllowWithTagCondition', 'DenyWithTagCondition', 'Deny'],
expectedPolicyEvaluation: {
verdict: 'Deny',
isImplicit: false,
},
},
{
policiesToEvaluate: ['DenyWithTagCondition', 'AllowWithTagCondition', 'Allow'],
expectedPolicyEvaluation: {
verdict: 'NeedTagConditionEval',
isImplicit: false,
},
},
];
TestMatrixV2.forEach(testCase => {
it(`policies evaluating individually to [${testCase.policiesToEvaluate.join(', ')}] `
+ `should return ${testCase.expectedPolicyEvaluation}`, () => {
requestContext = new RequestContext({}, {},
'my_favorite_bucket', undefined,
undefined, undefined, 'objectGet', 's3');
requestContext.setRequesterInfo({});
const result = evaluateAllPoliciesV2(
requestContext,
testCase.policiesToEvaluate.map(policyName => TestMatrixPolicies[policyName]),
log);
assert.deepStrictEqual(result, testCase.expectedPolicyEvaluation);
});
});
const TestMatrix = [ const TestMatrix = [
{ {
policiesToEvaluate: [], policiesToEvaluate: [],