Compare commits
2 Commits
developmen
...
w/8.0/feat
Author | SHA1 | Date |
---|---|---|
bert-e | 8d9507a5c8 | |
Dora Korpar | a7ac5fefe3 |
|
@ -467,6 +467,10 @@
|
||||||
"code": 400,
|
"code": 400,
|
||||||
"description": "The request was rejected because an invalid or out-of-range value was supplied for an input parameter."
|
"description": "The request was rejected because an invalid or out-of-range value was supplied for an input parameter."
|
||||||
},
|
},
|
||||||
|
"MalformedPolicy": {
|
||||||
|
"code": 400,
|
||||||
|
"description": "Policies must be valid JSON and the first byte must be '{'"
|
||||||
|
},
|
||||||
"_comment": "-------------- Special non-AWS S3 errors --------------",
|
"_comment": "-------------- Special non-AWS S3 errors --------------",
|
||||||
"MPUinProgress": {
|
"MPUinProgress": {
|
||||||
"code": 409,
|
"code": 409,
|
||||||
|
|
|
@ -2,11 +2,13 @@
|
||||||
|
|
||||||
const Ajv = require('ajv');
|
const Ajv = require('ajv');
|
||||||
const userPolicySchema = require('./userPolicySchema');
|
const userPolicySchema = require('./userPolicySchema');
|
||||||
|
const resourcePolicySchema = require('./resourcePolicySchema');
|
||||||
const errors = require('../errors');
|
const errors = require('../errors');
|
||||||
|
|
||||||
const ajValidate = new Ajv({ allErrors: true });
|
const ajValidate = new Ajv({ allErrors: true });
|
||||||
// compiles schema to functions and caches them for all cases
|
// compiles schema to functions and caches them for all cases
|
||||||
const userPolicyValidate = ajValidate.compile(userPolicySchema);
|
const userPolicyValidate = ajValidate.compile(userPolicySchema);
|
||||||
|
const resourcePolicyValidate = ajValidate.compile(resourcePolicySchema);
|
||||||
|
|
||||||
const errDict = {
|
const errDict = {
|
||||||
required: {
|
required: {
|
||||||
|
@ -24,33 +26,39 @@ const errDict = {
|
||||||
};
|
};
|
||||||
|
|
||||||
// parse ajv errors and return early with the first relevant error
|
// parse ajv errors and return early with the first relevant error
|
||||||
function _parseErrors(ajvErrors) {
|
function _parseErrors(ajvErrors, policyType) {
|
||||||
|
let parsedErr;
|
||||||
|
if (policyType === 'user') {
|
||||||
// deep copy is needed as we have to assign custom error description
|
// deep copy is needed as we have to assign custom error description
|
||||||
const parsedErr = Object.assign({}, errors.MalformedPolicyDocument);
|
parsedErr = Object.assign({}, errors.MalformedPolicyDocument);
|
||||||
parsedErr.description = 'Syntax errors in policy.';
|
parsedErr.description = 'Syntax errors in policy.';
|
||||||
|
}
|
||||||
|
if (policyType === 'resource') {
|
||||||
|
parsedErr = Object.assign({}, errors.MalformedPolicy);
|
||||||
|
}
|
||||||
ajvErrors.some(err => {
|
ajvErrors.some(err => {
|
||||||
const resource = err.dataPath;
|
const resource = err.dataPath;
|
||||||
const field = err.params ? err.params.missingProperty : undefined;
|
const field = err.params ? err.params.missingProperty : undefined;
|
||||||
const errType = err.keyword;
|
const errType = err.keyword;
|
||||||
if (errType === 'type' && (resource === '.Statement' ||
|
if (errType === 'type' && (resource === '.Statement' ||
|
||||||
resource === '.Statement.Resource' ||
|
resource.includes('.Resource') ||
|
||||||
resource === '.Statement.NotResource')) {
|
resource.includes('.NotResource'))) {
|
||||||
// skip this as this doesn't have enough error context
|
// skip this as this doesn't have enough error context
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (err.keyword === 'required' && field && errDict.required[field]) {
|
if (err.keyword === 'required' && field && errDict.required[field]) {
|
||||||
parsedErr.description = errDict.required[field];
|
parsedErr.description = errDict.required[field];
|
||||||
} else if (err.keyword === 'pattern' &&
|
} else if (err.keyword === 'pattern' &&
|
||||||
(resource === '.Statement.Action' ||
|
(resource.includes('.Action') ||
|
||||||
resource === '.Statement.NotAction')) {
|
resource.includes('.NotAction'))) {
|
||||||
parsedErr.description = errDict.pattern.Action;
|
parsedErr.description = errDict.pattern.Action;
|
||||||
} else if (err.keyword === 'pattern' &&
|
} else if (err.keyword === 'pattern' &&
|
||||||
(resource === '.Statement.Resource' ||
|
(resource.includes('.Resource') ||
|
||||||
resource === '.Statement.NotResource')) {
|
resource.includes('.NotResource'))) {
|
||||||
parsedErr.description = errDict.pattern.Resource;
|
parsedErr.description = errDict.pattern.Resource;
|
||||||
} else if (err.keyword === 'minItems' &&
|
} else if (err.keyword === 'minItems' &&
|
||||||
(resource === '.Statement.Resource' ||
|
(resource.includes('.Resource') ||
|
||||||
resource === '.Statement.NotResource')) {
|
resource.includes('.NotResource'))) {
|
||||||
parsedErr.description = errDict.minItems.Resource;
|
parsedErr.description = errDict.minItems.Resource;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
@ -77,12 +85,24 @@ function _validatePolicy(type, policy) {
|
||||||
}
|
}
|
||||||
userPolicyValidate(parseRes);
|
userPolicyValidate(parseRes);
|
||||||
if (userPolicyValidate.errors) {
|
if (userPolicyValidate.errors) {
|
||||||
return { error: _parseErrors(userPolicyValidate.errors),
|
return { error: _parseErrors(userPolicyValidate.errors, 'user'),
|
||||||
valid: false };
|
valid: false };
|
||||||
}
|
}
|
||||||
return { error: null, valid: true };
|
return { error: null, valid: true };
|
||||||
}
|
}
|
||||||
// TODO: add support for resource policies
|
if (type === 'resource') {
|
||||||
|
const parseRes = _safeJSONParse(policy);
|
||||||
|
if (parseRes instanceof Error) {
|
||||||
|
return { error: Object.assign({}, errors.MalformedPolicy),
|
||||||
|
valid: false };
|
||||||
|
}
|
||||||
|
resourcePolicyValidate(parseRes);
|
||||||
|
if (resourcePolicyValidate.errors) {
|
||||||
|
return { error: _parseErrors(resourcePolicyValidate.errors,
|
||||||
|
'resource'), valid: false };
|
||||||
|
}
|
||||||
|
return { error: null, valid: true };
|
||||||
|
}
|
||||||
return { error: errors.NotImplemented, valid: false };
|
return { error: errors.NotImplemented, valid: false };
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -0,0 +1,477 @@
|
||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||||
|
"type": "object",
|
||||||
|
"title": "AWS Bucket Policy schema.",
|
||||||
|
"description": "This schema describes a bucket policy per AWS policy grammar rules",
|
||||||
|
"definitions": {
|
||||||
|
"principalService": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"Service": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"backbeat"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
},
|
||||||
|
"principalCanonicalUser": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"CanonicalUser": {
|
||||||
|
"type": "string",
|
||||||
|
"pattern": "^[0-9a-z]{64}$"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
},
|
||||||
|
"principalAnonymous": {
|
||||||
|
"type": "string",
|
||||||
|
"pattern": "^\\*$"
|
||||||
|
},
|
||||||
|
"principalAWSAccountID": {
|
||||||
|
"type": "string",
|
||||||
|
"pattern": "^[0-9]{12}$"
|
||||||
|
},
|
||||||
|
"principalAWSAccountArn": {
|
||||||
|
"type": "string",
|
||||||
|
"pattern": "^arn:aws:iam::[0-9]{12}:root$"
|
||||||
|
},
|
||||||
|
"principalAWSUserArn": {
|
||||||
|
"type": "string",
|
||||||
|
"pattern": "^arn:aws:iam::[0-9]{12}:user/[\\w+=,.@ -]{1,64}$"
|
||||||
|
},
|
||||||
|
"principalAWSRoleArn": {
|
||||||
|
"type": "string",
|
||||||
|
"pattern": "^arn:aws:iam::[0-9]{12}:role/[\\w+=,.@ -]{1,64}$"
|
||||||
|
},
|
||||||
|
"principalAWSItem": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"AWS": {
|
||||||
|
"oneOf": [
|
||||||
|
{ "$ref": "#/definitions/principalAWSAccountID" },
|
||||||
|
{ "$ref": "#/definitions/principalAnonymous" },
|
||||||
|
{ "$ref": "#/definitions/principalAWSAccountArn" },
|
||||||
|
{ "$ref": "#/definitions/principalAWSUserArn" },
|
||||||
|
{ "$ref": "#/definitions/principalAWSRoleArn" },
|
||||||
|
{
|
||||||
|
"type": "array",
|
||||||
|
"minItems": 1,
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/principalAWSAccountID"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "array",
|
||||||
|
"minItems": 1,
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/principalAWSAccountArn"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "array",
|
||||||
|
"minItems": 1,
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/principalAWSRoleArn"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "array",
|
||||||
|
"minItems": 1,
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/principalAWSUserArn"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
},
|
||||||
|
"principalItem": {
|
||||||
|
"oneOf": [
|
||||||
|
{ "$ref": "#/definitions/principalAWSItem" },
|
||||||
|
{ "$ref": "#/definitions/principalAnonymous" },
|
||||||
|
{ "$ref": "#/definitions/principalService" },
|
||||||
|
{ "$ref": "#/definitions/principalCanonicalUser" }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"actionItem": {
|
||||||
|
"type": "string",
|
||||||
|
"pattern": "^[^*:]+:([^:])+|^\\*$"
|
||||||
|
},
|
||||||
|
"resourceItem": {
|
||||||
|
"type": "string",
|
||||||
|
"pattern": "^\\*|arn:(aws|scality)(:(\\*{1}|[a-z0-9\\*\\-]{2,})*?){3}:((?!\\$\\{\\}).)*?$"
|
||||||
|
},
|
||||||
|
"conditionKeys" : {
|
||||||
|
"properties": {
|
||||||
|
"aws:CurrentTime": {},
|
||||||
|
"aws:EpochTime": {},
|
||||||
|
"aws:MultiFactorAuthAge": {},
|
||||||
|
"aws:MultiFactorAuthPresent": {},
|
||||||
|
"aws:PrincipalArn": {},
|
||||||
|
"aws:PrincipalOrgId": {},
|
||||||
|
"aws:PrincipalTag/${TagKey}": {},
|
||||||
|
"aws:PrincipalType": {},
|
||||||
|
"aws:Referer": {},
|
||||||
|
"aws:RequestTag/${TagKey}": {},
|
||||||
|
"aws:RequestedRegion": {},
|
||||||
|
"aws:SecureTransport": {},
|
||||||
|
"aws:SourceAccount": {},
|
||||||
|
"aws:SourceArn": {},
|
||||||
|
"aws:SourceIp": {},
|
||||||
|
"aws:SourceVpc": {},
|
||||||
|
"aws:SourceVpce": {},
|
||||||
|
"aws:TagKeys": {},
|
||||||
|
"aws:TokenIssueTime": {},
|
||||||
|
"aws:UserAgent": {},
|
||||||
|
"aws:userid": {},
|
||||||
|
"aws:username": {},
|
||||||
|
"s3:ExistingJobOperation": {},
|
||||||
|
"s3:ExistingJobPriority": {},
|
||||||
|
"s3:ExistingObjectTag/<key>": {},
|
||||||
|
"s3:JobSuspendedCause": {},
|
||||||
|
"s3:LocationConstraint": {},
|
||||||
|
"s3:RequestJobOperation": {},
|
||||||
|
"s3:RequestJobPriority": {},
|
||||||
|
"s3:RequestObjectTag/<key>": {},
|
||||||
|
"s3:RequestObjectTagKeys": {},
|
||||||
|
"s3:VersionId": {},
|
||||||
|
"s3:authtype": {},
|
||||||
|
"s3:delimiter": {},
|
||||||
|
"s3:locationconstraint": {},
|
||||||
|
"s3:max-keys": {},
|
||||||
|
"s3:object-lock-legal-hold": {},
|
||||||
|
"s3:object-lock-mode": {},
|
||||||
|
"s3:object-lock-remaining-retention-days": {},
|
||||||
|
"s3:object-lock-retain-until-date": {},
|
||||||
|
"s3:prefix": {},
|
||||||
|
"s3:signatureage": {},
|
||||||
|
"s3:signatureversion": {},
|
||||||
|
"s3:versionid": {},
|
||||||
|
"s3:x-amz-acl": {},
|
||||||
|
"s3:x-amz-content-sha256": {},
|
||||||
|
"s3:x-amz-copy-source": {},
|
||||||
|
"s3:x-amz-grant-full-control": {},
|
||||||
|
"s3:x-amz-grant-read": {},
|
||||||
|
"s3:x-amz-grant-read-acp": {},
|
||||||
|
"s3:x-amz-grant-write": {},
|
||||||
|
"s3:x-amz-grant-write-acp": {},
|
||||||
|
"s3:x-amz-metadata-directive": {},
|
||||||
|
"s3:x-amz-server-side-encryption": {},
|
||||||
|
"s3:x-amz-server-side-encryption-aws-kms-key-id": {},
|
||||||
|
"s3:x-amz-storage-class": {},
|
||||||
|
"s3:x-amz-website-redirect-location": {}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
},
|
||||||
|
"conditions": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"ArnEquals": {
|
||||||
|
"type": "object"
|
||||||
|
},
|
||||||
|
"ArnEqualsIfExists": {
|
||||||
|
"type": "object"
|
||||||
|
},
|
||||||
|
"ArnLike": {
|
||||||
|
"type": "object"
|
||||||
|
},
|
||||||
|
"ArnLikeIfExists": {
|
||||||
|
"type": "object"
|
||||||
|
},
|
||||||
|
"ArnNotEquals": {
|
||||||
|
"type": "object"
|
||||||
|
},
|
||||||
|
"ArnNotEqualsIfExists": {
|
||||||
|
"type": "object"
|
||||||
|
},
|
||||||
|
"ArnNotLike": {
|
||||||
|
"type": "object"
|
||||||
|
},
|
||||||
|
"ArnNotLikeIfExists": {
|
||||||
|
"type": "object"
|
||||||
|
},
|
||||||
|
"BinaryEquals": {
|
||||||
|
"type": "object"
|
||||||
|
},
|
||||||
|
"BinaryEqualsIfExists": {
|
||||||
|
"type": "object"
|
||||||
|
},
|
||||||
|
"BinaryNotEquals": {
|
||||||
|
"type": "object"
|
||||||
|
},
|
||||||
|
"BinaryNotEqualsIfExists": {
|
||||||
|
"type": "object"
|
||||||
|
},
|
||||||
|
"Bool": {
|
||||||
|
"type": "object"
|
||||||
|
},
|
||||||
|
"BoolIfExists": {
|
||||||
|
"type": "object"
|
||||||
|
},
|
||||||
|
"DateEquals": {
|
||||||
|
"type": "object"
|
||||||
|
},
|
||||||
|
"DateEqualsIfExists": {
|
||||||
|
"type": "object"
|
||||||
|
},
|
||||||
|
"DateGreaterThan": {
|
||||||
|
"type": "object"
|
||||||
|
},
|
||||||
|
"DateGreaterThanEquals": {
|
||||||
|
"type": "object"
|
||||||
|
},
|
||||||
|
"DateGreaterThanEqualsIfExists": {
|
||||||
|
"type": "object"
|
||||||
|
},
|
||||||
|
"DateGreaterThanIfExists": {
|
||||||
|
"type": "object"
|
||||||
|
},
|
||||||
|
"DateLessThan": {
|
||||||
|
"type": "object"
|
||||||
|
},
|
||||||
|
"DateLessThanEquals": {
|
||||||
|
"type": "object"
|
||||||
|
},
|
||||||
|
"DateLessThanEqualsIfExists": {
|
||||||
|
"type": "object"
|
||||||
|
},
|
||||||
|
"DateLessThanIfExists": {
|
||||||
|
"type": "object"
|
||||||
|
},
|
||||||
|
"DateNotEquals": {
|
||||||
|
"type": "object"
|
||||||
|
},
|
||||||
|
"DateNotEqualsIfExists": {
|
||||||
|
"type": "object"
|
||||||
|
},
|
||||||
|
"IpAddress": {
|
||||||
|
"type": "object"
|
||||||
|
},
|
||||||
|
"IpAddressIfExists": {
|
||||||
|
"type": "object"
|
||||||
|
},
|
||||||
|
"NotIpAddress": {
|
||||||
|
"type": "object"
|
||||||
|
},
|
||||||
|
"NotIpAddressIfExists": {
|
||||||
|
"type": "object"
|
||||||
|
},
|
||||||
|
"Null": {
|
||||||
|
"type": "object"
|
||||||
|
},
|
||||||
|
"NumericEquals": {
|
||||||
|
"type": "object"
|
||||||
|
},
|
||||||
|
"NumericEqualsIfExists": {
|
||||||
|
"type": "object"
|
||||||
|
},
|
||||||
|
"NumericGreaterThan": {
|
||||||
|
"type": "object"
|
||||||
|
},
|
||||||
|
"NumericGreaterThanEquals": {
|
||||||
|
"type": "object"
|
||||||
|
},
|
||||||
|
"NumericGreaterThanEqualsIfExists": {
|
||||||
|
"type": "object"
|
||||||
|
},
|
||||||
|
"NumericGreaterThanIfExists": {
|
||||||
|
"type": "object"
|
||||||
|
},
|
||||||
|
"NumericLessThan": {
|
||||||
|
"type": "object"
|
||||||
|
},
|
||||||
|
"NumericLessThanEquals": {
|
||||||
|
"type": "object"
|
||||||
|
},
|
||||||
|
"NumericLessThanEqualsIfExists": {
|
||||||
|
"type": "object"
|
||||||
|
},
|
||||||
|
"NumericLessThanIfExists": {
|
||||||
|
"type": "object"
|
||||||
|
},
|
||||||
|
"NumericNotEquals": {
|
||||||
|
"type": "object"
|
||||||
|
},
|
||||||
|
"NumericNotEqualsIfExists": {
|
||||||
|
"type": "object"
|
||||||
|
},
|
||||||
|
"StringEquals": {
|
||||||
|
"type": "object"
|
||||||
|
},
|
||||||
|
"StringEqualsIfExists": {
|
||||||
|
"type": "object"
|
||||||
|
},
|
||||||
|
"StringEqualsIgnoreCase": {
|
||||||
|
"type": "object"
|
||||||
|
},
|
||||||
|
"StringEqualsIgnoreCaseIfExists": {
|
||||||
|
"type": "object"
|
||||||
|
},
|
||||||
|
"StringLike": {
|
||||||
|
"type": "object"
|
||||||
|
},
|
||||||
|
"StringLikeIfExists": {
|
||||||
|
"type": "object"
|
||||||
|
},
|
||||||
|
"StringNotEquals": {
|
||||||
|
"type": "object"
|
||||||
|
},
|
||||||
|
"StringNotEqualsIfExists": {
|
||||||
|
"type": "object"
|
||||||
|
},
|
||||||
|
"StringNotEqualsIgnoreCase": {
|
||||||
|
"type": "object"
|
||||||
|
},
|
||||||
|
"StringNotEqualsIgnoreCaseIfExists": {
|
||||||
|
"type": "object"
|
||||||
|
},
|
||||||
|
"StringNotLike": {
|
||||||
|
"type": "object"
|
||||||
|
},
|
||||||
|
"StringNotLikeIfExists": {
|
||||||
|
"type": "object"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"properties": {
|
||||||
|
"Version": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"2012-10-17"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"Statement": {
|
||||||
|
"oneOf": [
|
||||||
|
{
|
||||||
|
"type": [
|
||||||
|
"array"
|
||||||
|
],
|
||||||
|
"minItems": 1,
|
||||||
|
"items": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"Sid": {
|
||||||
|
"type": "string",
|
||||||
|
"pattern": "^[a-zA-Z0-9]+$"
|
||||||
|
},
|
||||||
|
"Action": {
|
||||||
|
"oneOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/actionItem"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/actionItem"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"Effect": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"Allow",
|
||||||
|
"Deny"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"Principal": {
|
||||||
|
"$ref": "#/definitions/principalItem"
|
||||||
|
},
|
||||||
|
"Resource": {
|
||||||
|
"oneOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/resourceItem"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/resourceItem"
|
||||||
|
},
|
||||||
|
"minItems": 1
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"Condition": {
|
||||||
|
"$ref": "#/definitions/conditions"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"Action",
|
||||||
|
"Effect",
|
||||||
|
"Principal",
|
||||||
|
"Resource"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": [
|
||||||
|
"object"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"Sid": {
|
||||||
|
"type": "string",
|
||||||
|
"pattern": "^[a-zA-Z0-9]+$"
|
||||||
|
},
|
||||||
|
"Action": {
|
||||||
|
"oneOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/actionItem"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/actionItem"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"Effect": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"Allow",
|
||||||
|
"Deny"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"Principal": {
|
||||||
|
"$ref": "#/definitions/principalItem"
|
||||||
|
},
|
||||||
|
"Resource": {
|
||||||
|
"oneOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/resourceItem"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/resourceItem"
|
||||||
|
},
|
||||||
|
"minItems": 1
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"Condition": {
|
||||||
|
"$ref": "#/definitions/conditions"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"Action",
|
||||||
|
"Effect",
|
||||||
|
"Resource",
|
||||||
|
"Principal"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"Version",
|
||||||
|
"Statement"
|
||||||
|
],
|
||||||
|
"additionalProperties": false
|
||||||
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"title": "AWS Policy schema.",
|
"title": "AWS IAM Policy schema.",
|
||||||
"description": "This schema describes a user policy per AWS policy grammar rules",
|
"description": "This schema describes a user policy per AWS policy grammar rules",
|
||||||
"definitions": {
|
"definitions": {
|
||||||
"principalService": {
|
"principalService": {
|
||||||
|
|
|
@ -32,6 +32,9 @@ const _actionMap = {
|
||||||
bucketPutLifecycle: 's3:PutLifecycleConfiguration',
|
bucketPutLifecycle: 's3:PutLifecycleConfiguration',
|
||||||
bucketGetLifecycle: 's3:GetLifecycleConfiguration',
|
bucketGetLifecycle: 's3:GetLifecycleConfiguration',
|
||||||
bucketDeleteLifecycle: 's3:DeleteLifecycleConfiguration',
|
bucketDeleteLifecycle: 's3:DeleteLifecycleConfiguration',
|
||||||
|
bucketPutPolicy: 's3:PutBucketPolicy',
|
||||||
|
bucketGetPolicy: 's3:GetBucketPolicy',
|
||||||
|
bucketDeletePolicy: 's3:DeleteBucketPolicy',
|
||||||
completeMultipartUpload: 's3:PutObject',
|
completeMultipartUpload: 's3:PutObject',
|
||||||
initiateMultipartUpload: 's3:PutObject',
|
initiateMultipartUpload: 's3:PutObject',
|
||||||
listMultipartUploads: 's3:ListBucketMultipartUploads',
|
listMultipartUploads: 's3:ListBucketMultipartUploads',
|
||||||
|
|
|
@ -4,8 +4,9 @@ const assert = require('assert');
|
||||||
const policyValidator = require('../../../lib/policy/policyValidator');
|
const policyValidator = require('../../../lib/policy/policyValidator');
|
||||||
const errors = require('../../../lib/errors');
|
const errors = require('../../../lib/errors');
|
||||||
const validateUserPolicy = policyValidator.validateUserPolicy;
|
const validateUserPolicy = policyValidator.validateUserPolicy;
|
||||||
|
const validateResourcePolicy = policyValidator.validateResourcePolicy;
|
||||||
const successRes = { error: null, valid: true };
|
const successRes = { error: null, valid: true };
|
||||||
const samplePolicy = {
|
const sampleUserPolicy = {
|
||||||
Version: '2012-10-17',
|
Version: '2012-10-17',
|
||||||
Statement: {
|
Statement: {
|
||||||
Sid: 'FooBar1234',
|
Sid: 'FooBar1234',
|
||||||
|
@ -15,6 +16,19 @@ const samplePolicy = {
|
||||||
Condition: { NumericLessThanEquals: { 's3:max-keys': '10' } },
|
Condition: { NumericLessThanEquals: { 's3:max-keys': '10' } },
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
const sampleResourcePolicy = {
|
||||||
|
Version: '2012-10-17',
|
||||||
|
Statement: [
|
||||||
|
{
|
||||||
|
Sid: 'ResourcePolicy1',
|
||||||
|
Effect: 'Allow',
|
||||||
|
Action: 's3:ListBucket',
|
||||||
|
Resource: 'arn:aws:s3:::example-bucket',
|
||||||
|
Condition: { StringLike: { 's3:prefix': 'foo' } },
|
||||||
|
Principal: '*',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
const errDict = {
|
const errDict = {
|
||||||
required: {
|
required: {
|
||||||
|
@ -30,45 +44,84 @@ const errDict = {
|
||||||
Resource: 'Policy statement must contain resources.',
|
Resource: 'Policy statement must contain resources.',
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
let policy;
|
|
||||||
|
|
||||||
function failRes(errDescription) {
|
function failRes(policyType, errDescription) {
|
||||||
const error = Object.assign({}, errors.MalformedPolicyDocument);
|
let error;
|
||||||
|
if (policyType === 'user') {
|
||||||
|
error = Object.assign({}, errors.MalformedPolicyDocument);
|
||||||
|
}
|
||||||
|
if (policyType === 'resource') {
|
||||||
|
error = Object.assign({}, errors.MalformedPolicy);
|
||||||
|
}
|
||||||
error.description = errDescription || error.description;
|
error.description = errDescription || error.description;
|
||||||
return { error, valid: false };
|
return { error, valid: false };
|
||||||
}
|
}
|
||||||
|
|
||||||
function check(input, expected) {
|
function check(input, expected, policyType) {
|
||||||
const result = validateUserPolicy(JSON.stringify(input));
|
let result;
|
||||||
|
if (policyType === 'user') {
|
||||||
|
result = validateUserPolicy(JSON.stringify(input));
|
||||||
|
}
|
||||||
|
if (policyType === 'resource') {
|
||||||
|
result = validateResourcePolicy(JSON.stringify(input));
|
||||||
|
}
|
||||||
assert.deepStrictEqual(result, expected);
|
assert.deepStrictEqual(result, expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let userPolicy;
|
||||||
|
let resourcePolicy;
|
||||||
|
const user = 'user';
|
||||||
|
const resource = 'resource';
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
policy = JSON.parse(JSON.stringify(samplePolicy));
|
userPolicy = JSON.parse(JSON.stringify(sampleUserPolicy));
|
||||||
|
resourcePolicy = JSON.parse(JSON.stringify(sampleResourcePolicy));
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Policies validation - Invalid JSON', () => {
|
describe('Policies validation - Invalid JSON', () => {
|
||||||
it('should return error for invalid JSON', () => {
|
it('should return error for invalid user policy JSON', () => {
|
||||||
const result = validateUserPolicy('{"Version":"2012-10-17",' +
|
const result = validateUserPolicy('{"Version":"2012-10-17",' +
|
||||||
'"Statement":{"Effect":"Allow""Action":"s3:PutObject",' +
|
'"Statement":{"Effect":"Allow""Action":"s3:PutObject",' +
|
||||||
'"Resource":"arn:aws:s3*"}}');
|
'"Resource":"arn:aws:s3*"}}');
|
||||||
assert.deepStrictEqual(result, failRes());
|
assert.deepStrictEqual(result, failRes(user));
|
||||||
|
});
|
||||||
|
it('should return error for invaild resource policy JSON', () => {
|
||||||
|
const result = validateResourcePolicy('{"Version":"2012-10-17",' +
|
||||||
|
'"Statement":{"Effect":"Allow""Action":"s3:PutObject",' +
|
||||||
|
'"Resource":"arn:aws:s3*"}}');
|
||||||
|
assert.deepStrictEqual(result, failRes(resource));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Policies validation - Version', () => {
|
describe('Policies validation - Version', () => {
|
||||||
it('should validate with version date 2012-10-17', () => {
|
it('should validate user policy with version date 2012-10-17', () => {
|
||||||
check(policy, successRes);
|
check(userPolicy, successRes, user);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return error for other dates', () => {
|
it('should validate resource policy with version date 2012-10-17', () => {
|
||||||
policy.Version = '2012-11-17';
|
check(resourcePolicy, successRes, 'resource');
|
||||||
check(policy, failRes());
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return error if Version field is missing', () => {
|
it('user policy should return error for other dates', () => {
|
||||||
policy.Version = undefined;
|
userPolicy.Version = '2012-11-17';
|
||||||
check(policy, failRes(errDict.required.Version));
|
check(userPolicy, failRes(user), user);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('resource policy should return error for other dates', () => {
|
||||||
|
resourcePolicy.Version = '2012-11-17';
|
||||||
|
check(resourcePolicy, failRes(resource), resource);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return error if Version field in user policy is missing', () => {
|
||||||
|
userPolicy.Version = undefined;
|
||||||
|
check(userPolicy, failRes(user, errDict.required.Version), user);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return error if Version field in resource policy is missing',
|
||||||
|
() => {
|
||||||
|
resourcePolicy.Version = undefined;
|
||||||
|
check(resourcePolicy, failRes(resource, errDict.required.Version),
|
||||||
|
resource);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -77,20 +130,24 @@ describe('Policies validation - Principal', () => {
|
||||||
{
|
{
|
||||||
name: 'an account id',
|
name: 'an account id',
|
||||||
value: { AWS: '111111111111' },
|
value: { AWS: '111111111111' },
|
||||||
|
policyType: [user, resource],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'anonymous user AWS form',
|
name: 'anonymous user AWS form',
|
||||||
value: { AWS: '*' },
|
value: { AWS: '*' },
|
||||||
|
policyType: [user, resource],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'an account arn',
|
name: 'an account arn',
|
||||||
value: { AWS: 'arn:aws:iam::111111111111:root' },
|
value: { AWS: 'arn:aws:iam::111111111111:root' },
|
||||||
|
policyType: [user, resource],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'multiple account id',
|
name: 'multiple account id',
|
||||||
value: {
|
value: {
|
||||||
AWS: ['111111111111', '111111111112'],
|
AWS: ['111111111111', '111111111112'],
|
||||||
},
|
},
|
||||||
|
policyType: [user, resource],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'multiple account arn',
|
name: 'multiple account arn',
|
||||||
|
@ -100,14 +157,17 @@ describe('Policies validation - Principal', () => {
|
||||||
'arn:aws:iam::111111111112:root',
|
'arn:aws:iam::111111111112:root',
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
policyType: [user, resource],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'anonymous user as string',
|
name: 'anonymous user as string',
|
||||||
value: '*',
|
value: '*',
|
||||||
|
policyType: [user, resource],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'user arn',
|
name: 'user arn',
|
||||||
value: { AWS: 'arn:aws:iam::111111111111:user/alex' },
|
value: { AWS: 'arn:aws:iam::111111111111:user/alex' },
|
||||||
|
policyType: [user, resource],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'multiple user arns',
|
name: 'multiple user arns',
|
||||||
|
@ -117,12 +177,14 @@ describe('Policies validation - Principal', () => {
|
||||||
'arn:aws:iam::111111111111:user/thibault',
|
'arn:aws:iam::111111111111:user/thibault',
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
policyType: [user, resource],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'role arn',
|
name: 'role arn',
|
||||||
value: {
|
value: {
|
||||||
AWS: 'arn:aws:iam::111111111111:role/dev',
|
AWS: 'arn:aws:iam::111111111111:role/dev',
|
||||||
},
|
},
|
||||||
|
policyType: [user, resource],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'multiple role arn',
|
name: 'multiple role arn',
|
||||||
|
@ -132,6 +194,7 @@ describe('Policies validation - Principal', () => {
|
||||||
'arn:aws:iam::111111111111:role/prod',
|
'arn:aws:iam::111111111111:role/prod',
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
policyType: [user, resource],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'saml provider',
|
name: 'saml provider',
|
||||||
|
@ -139,57 +202,84 @@ describe('Policies validation - Principal', () => {
|
||||||
Federated:
|
Federated:
|
||||||
'arn:aws:iam::111111111111:saml-provider/mysamlprovider',
|
'arn:aws:iam::111111111111:saml-provider/mysamlprovider',
|
||||||
},
|
},
|
||||||
|
policyType: [user],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'with backbeat service',
|
name: 'with backbeat service',
|
||||||
value: { Service: 'backbeat' },
|
value: { Service: 'backbeat' },
|
||||||
|
policyType: [user, resource],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'with canonical user id',
|
||||||
|
value: { CanonicalUser:
|
||||||
|
'1examplecanonicalid12345678909876' +
|
||||||
|
'54321qwerty12345asdfg67890z1x2c' },
|
||||||
|
policyType: [resource],
|
||||||
},
|
},
|
||||||
].forEach(test => {
|
].forEach(test => {
|
||||||
it(`should allow principal field with ${test.name}`, () => {
|
if (test.policyType.includes(user)) {
|
||||||
policy.Statement.Principal = test.value;
|
it(`should allow user policy principal field with ${test.name}`,
|
||||||
delete policy.Statement.Resource;
|
() => {
|
||||||
check(policy, successRes);
|
userPolicy.Statement.Principal = test.value;
|
||||||
|
delete userPolicy.Statement.Resource;
|
||||||
|
check(userPolicy, successRes, user);
|
||||||
});
|
});
|
||||||
|
|
||||||
it(`shoud allow notPrincipal field with ${test.name}`, () => {
|
it(`should allow user policy notPrincipal field with ${test.name}`,
|
||||||
policy.Statement.NotPrincipal = test.value;
|
() => {
|
||||||
delete policy.Statement.Resource;
|
userPolicy.Statement.NotPrincipal = test.value;
|
||||||
check(policy, successRes);
|
delete userPolicy.Statement.Resource;
|
||||||
|
check(userPolicy, successRes, user);
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
if (test.policyType.includes(resource)) {
|
||||||
|
it(`should allow resource policy principal field with ${test.name}`,
|
||||||
|
() => {
|
||||||
|
resourcePolicy.Statement[0].Principal = test.value;
|
||||||
|
check(resourcePolicy, successRes, resource);
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
name: 'wrong format account id',
|
name: 'wrong format account id',
|
||||||
value: { AWS: '11111111111z' },
|
value: { AWS: '11111111111z' },
|
||||||
|
policyType: [user, resource],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'empty string',
|
name: 'empty string',
|
||||||
value: '',
|
value: '',
|
||||||
|
policyType: [user, resource],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'anonymous user federated form',
|
name: 'anonymous user federated form',
|
||||||
value: { federated: '*' },
|
value: { federated: '*' },
|
||||||
|
policyType: [user, resource],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'wildcard in ressource',
|
name: 'wildcard in resource',
|
||||||
value: { AWS: 'arn:aws:iam::111111111111:user/*' },
|
value: { AWS: 'arn:aws:iam::111111111111:user/*' },
|
||||||
|
policyType: [user, resource],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'a malformed account arn',
|
name: 'a malformed account arn',
|
||||||
value: { AWS: 'arn:aws:iam::111111111111:' },
|
value: { AWS: 'arn:aws:iam::111111111111:' },
|
||||||
|
policyType: [user, resource],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'multiple malformed account id',
|
name: 'multiple malformed account id',
|
||||||
value: {
|
value: {
|
||||||
AWS: ['1111111111z1', '1111z1111112'],
|
AWS: ['1111111111z1', '1111z1111112'],
|
||||||
},
|
},
|
||||||
|
policyType: [user, resource],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'multiple anonymous',
|
name: 'multiple anonymous',
|
||||||
value: {
|
value: {
|
||||||
AWS: ['*', '*'],
|
AWS: ['*', '*'],
|
||||||
},
|
},
|
||||||
|
policyType: [user, resource],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'multiple malformed account arn',
|
name: 'multiple malformed account arn',
|
||||||
|
@ -199,18 +289,22 @@ describe('Policies validation - Principal', () => {
|
||||||
'arn:aws:iam::111111111112:',
|
'arn:aws:iam::111111111112:',
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
policyType: [user, resource],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'account id as a string',
|
name: 'account id as a string',
|
||||||
value: '111111111111',
|
value: '111111111111',
|
||||||
|
policyType: [user, resource],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'account arn as a string',
|
name: 'account arn as a string',
|
||||||
value: 'arn:aws:iam::111111111111:root',
|
value: 'arn:aws:iam::111111111111:root',
|
||||||
|
policyType: [user, resource],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'user arn as a string',
|
name: 'user arn as a string',
|
||||||
value: 'arn:aws:iam::111111111111:user/alex',
|
value: 'arn:aws:iam::111111111111:user/alex',
|
||||||
|
policyType: [user, resource],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'multiple malformed user arns',
|
name: 'multiple malformed user arns',
|
||||||
|
@ -220,12 +314,14 @@ describe('Policies validation - Principal', () => {
|
||||||
'arn:aws:iam::111111111111:user/',
|
'arn:aws:iam::111111111111:user/',
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
policyType: [user, resource],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'malformed role arn',
|
name: 'malformed role arn',
|
||||||
value: {
|
value: {
|
||||||
AWS: 'arn:aws:iam::111111111111:role/',
|
AWS: 'arn:aws:iam::111111111111:role/',
|
||||||
},
|
},
|
||||||
|
policyType: [user, resource],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'multiple malformed role arn',
|
name: 'multiple malformed role arn',
|
||||||
|
@ -235,36 +331,84 @@ describe('Policies validation - Principal', () => {
|
||||||
'arn:aws:iam::11111111z111:role/prod',
|
'arn:aws:iam::11111111z111:role/prod',
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
policyType: [user, resource],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'saml provider as a string',
|
name: 'saml provider as a string',
|
||||||
value: 'arn:aws:iam::111111111111:saml-provider/mysamlprovider',
|
value: 'arn:aws:iam::111111111111:saml-provider/mysamlprovider',
|
||||||
|
policyType: [user],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'with other service than backbeat',
|
name: 'with other service than backbeat',
|
||||||
value: { Service: 'non-existent-service' },
|
value: { Service: 'non-existent-service' },
|
||||||
|
policyType: [user, resource],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'invalid canonical user',
|
||||||
|
value: { CanonicalUser:
|
||||||
|
'12345invalid-canonical-id$$$//098' +
|
||||||
|
'7654321poiu1q2w3e4r5t6y7u8i9o0p' },
|
||||||
|
policyType: [resource],
|
||||||
},
|
},
|
||||||
].forEach(test => {
|
].forEach(test => {
|
||||||
it(`should fail with ${test.name}`, () => {
|
if (test.policyType.includes(user)) {
|
||||||
policy.Statement.Principal = test.value;
|
it(`user policy should fail with ${test.name}`, () => {
|
||||||
delete policy.Statement.Resource;
|
userPolicy.Statement.Principal = test.value;
|
||||||
check(policy, failRes());
|
delete userPolicy.Statement.Resource;
|
||||||
|
check(userPolicy, failRes(user), user);
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
if (test.policyType.includes(resource)) {
|
||||||
|
it(`resource policy should fail with ${test.name}`, () => {
|
||||||
|
resourcePolicy.Statement[0].Principal = test.value;
|
||||||
|
check(resourcePolicy, failRes(resource), resource);
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not allow Resource field', () => {
|
it('should not allow Resource field', () => {
|
||||||
policy.Statement.Principal = '*';
|
userPolicy.Statement.Principal = '*';
|
||||||
check(policy, failRes());
|
check(userPolicy, failRes(user), user);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Policies validation - Statement', () => {
|
describe('Policies validation - Statement', () => {
|
||||||
it('should succeed for a valid object', () => {
|
[
|
||||||
check(policy, successRes);
|
{
|
||||||
|
name: 'should return error for undefined',
|
||||||
|
value: undefined,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'should return an error for an empty list',
|
||||||
|
value: [],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'should return an error for an empty object',
|
||||||
|
value: {},
|
||||||
|
errMessage: errDict.required.Action,
|
||||||
|
},
|
||||||
|
].forEach(test => {
|
||||||
|
it(`user policy ${test.name}`, () => {
|
||||||
|
userPolicy.Statement = test.value;
|
||||||
|
check(userPolicy, failRes(user, test.errMessage), user);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should succeed for a valid array', () => {
|
it(`resource policy ${test.name}`, () => {
|
||||||
policy.Statement = [
|
resourcePolicy.Statement = test.value;
|
||||||
|
check(resourcePolicy, failRes(resource, test.errMessage), resource);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('user policy should succeed for a valid object', () => {
|
||||||
|
check(userPolicy, successRes, user);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('resource policy should succeed for a valid object', () => {
|
||||||
|
check(resourcePolicy, successRes, resource);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('user policy should succeed for a valid object', () => {
|
||||||
|
userPolicy.Statement = [
|
||||||
{
|
{
|
||||||
Effect: 'Allow',
|
Effect: 'Allow',
|
||||||
Action: 's3:PutObject',
|
Action: 's3:PutObject',
|
||||||
|
@ -276,255 +420,373 @@ describe('Policies validation - Statement', () => {
|
||||||
Resource: 'arn:aws:s3:::my_bucket/uploads/widgetco/*',
|
Resource: 'arn:aws:s3:::my_bucket/uploads/widgetco/*',
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
check(policy, successRes);
|
check(userPolicy, successRes, user);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return an error for undefined', () => {
|
it('resource policy should succeed for a valid object', () => {
|
||||||
policy.Statement = undefined;
|
resourcePolicy.Statement = [
|
||||||
check(policy, failRes());
|
{
|
||||||
|
Effect: 'Allow',
|
||||||
|
Action: 's3:PutObject',
|
||||||
|
Resource: 'arn:aws:s3:::my_bucket/uploads/widgetco/*',
|
||||||
|
Principal: '*',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Effect: 'Deny',
|
||||||
|
Action: 's3:DeleteObject',
|
||||||
|
Resource: 'arn:aws:s3:::my_bucket/uploads/widgetco/*',
|
||||||
|
Principal: '*',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
check(resourcePolicy, successRes, resource);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return an error for an empty list', () => {
|
[
|
||||||
policy.Statement = [];
|
{
|
||||||
check(policy, failRes());
|
name: 'should return error for missing a required field - Action',
|
||||||
|
toDelete: ['Action'],
|
||||||
|
expected: 'fail',
|
||||||
|
errMessage: errDict.required.Action,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'should return error for missing a required field - Effect',
|
||||||
|
toDelete: ['Effect'],
|
||||||
|
expected: 'fail',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'should return error for missing required field - Resource',
|
||||||
|
toDelete: ['Resource'],
|
||||||
|
expected: 'fail',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'should return error for missing multiple required fields',
|
||||||
|
toDelete: ['Effect', 'Resource'],
|
||||||
|
expected: 'fail',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'should succeed w optional fields missing - Sid, Condition',
|
||||||
|
toDelete: ['Sid', 'Condition'],
|
||||||
|
expected: successRes,
|
||||||
|
},
|
||||||
|
].forEach(test => {
|
||||||
|
it(`user policy ${test.name}`, () => {
|
||||||
|
test.toDelete.forEach(p => delete userPolicy.Statement[p]);
|
||||||
|
if (test.expected === 'fail') {
|
||||||
|
check(userPolicy, failRes(user, test.errMessage), user);
|
||||||
|
} else {
|
||||||
|
check(userPolicy, test.expected, user);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return an error for an empty object', () => {
|
it(`resource policy ${test.name}`, () => {
|
||||||
policy.Statement = {};
|
test.toDelete.forEach(p => delete resourcePolicy.Statement[0][p]);
|
||||||
check(policy, failRes(errDict.required.Action));
|
if (test.expected === 'fail') {
|
||||||
|
check(resourcePolicy, failRes(resource, test.errMessage),
|
||||||
|
resource);
|
||||||
|
} else {
|
||||||
|
check(resourcePolicy, test.expected, resource);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return an error for missing a required field - Action', () => {
|
|
||||||
delete policy.Statement.Action;
|
|
||||||
check(policy, failRes(errDict.required.Action));
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return an error for missing a required field - Effect', () => {
|
|
||||||
delete policy.Statement.Effect;
|
|
||||||
check(policy, failRes());
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return an error for missing a required field - Resource', () => {
|
|
||||||
delete policy.Statement.Resource;
|
|
||||||
check(policy, failRes());
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return an error for missing multiple required fields', () => {
|
|
||||||
delete policy.Statement.Effect;
|
|
||||||
delete policy.Statement.Resource;
|
|
||||||
check(policy, failRes());
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should succeed with optional fields missing - Sid, Condition', () => {
|
|
||||||
delete policy.Statement.Sid;
|
|
||||||
delete policy.Statement.Condition;
|
|
||||||
check(policy, successRes);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Policies validation - Statement::Sid_block', () => {
|
describe('Policies validation - Statement::Sid_block', () => {
|
||||||
it('should succeed if Sid is any alphanumeric string', () => {
|
it('user policy should succeed if Sid is any alphanumeric string', () => {
|
||||||
check(policy, successRes);
|
check(userPolicy, successRes, user);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should fail if Sid is not a valid format', () => {
|
it('resource policy should succeed if Sid is any alphanumeric string',
|
||||||
policy.Statement.Sid = 'foo bar()';
|
() => {
|
||||||
check(policy, failRes());
|
check(resourcePolicy, successRes, resource);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should fail if Sid is not a string', () => {
|
it('user policy should fail if Sid is not a valid format', () => {
|
||||||
policy.Statement.Sid = 1234;
|
userPolicy.Statement.Sid = 'foo bar()';
|
||||||
check(policy, failRes());
|
check(userPolicy, failRes(user), user);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('resource policy should fail if Sid is not a valid format', () => {
|
||||||
|
resourcePolicy.Statement[0].Sid = 'foo bar()';
|
||||||
|
check(resourcePolicy, failRes(resource), resource);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('user policy should fail if Sid is not a string', () => {
|
||||||
|
userPolicy.Statement.Sid = 1234;
|
||||||
|
check(userPolicy, failRes(user), user);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('resource policy should fail if Sid is not a string', () => {
|
||||||
|
resourcePolicy.Statement[0].Sid = 1234;
|
||||||
|
check(resourcePolicy, failRes(resource), resource);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Policies validation - Statement::Effect_block', () => {
|
describe('Policies validation - Statement::Effect_block', () => {
|
||||||
it('should succeed for Allow', () => {
|
it('user policy should succeed for Allow', () => {
|
||||||
check(policy, successRes);
|
check(userPolicy, successRes, user);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should succeed for Deny', () => {
|
it('resource policy should succeed for Allow', () => {
|
||||||
policy.Statement.Effect = 'Deny';
|
check(resourcePolicy, successRes, resource);
|
||||||
check(policy, successRes);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should fail for strings other than Allow/Deny', () => {
|
it('user policy should succeed for Deny', () => {
|
||||||
policy.Statement.Effect = 'Reject';
|
userPolicy.Statement.Effect = 'Deny';
|
||||||
check(policy, failRes());
|
check(userPolicy, successRes, user);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should fail if Effect is not a string', () => {
|
it('resource policy should succeed for Deny', () => {
|
||||||
policy.Statement.Effect = 1;
|
resourcePolicy.Statement[0].Effect = 'Deny';
|
||||||
check(policy, failRes());
|
check(resourcePolicy, successRes, resource);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('user policy should fail for strings other than Allow/Deny', () => {
|
||||||
|
userPolicy.Statement.Effect = 'Reject';
|
||||||
|
check(userPolicy, failRes(user), user);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('resource policy should fail for strings other than Allow/Deny', () => {
|
||||||
|
resourcePolicy.Statement[0].Effect = 'Reject';
|
||||||
|
check(resourcePolicy, failRes(resource), resource);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('user policy should fail if Effect is not a string', () => {
|
||||||
|
userPolicy.Statement.Effect = 1;
|
||||||
|
check(userPolicy, failRes(user), user);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('resource policy should fail if Effect is not a string', () => {
|
||||||
|
resourcePolicy.Statement[0].Effect = 1;
|
||||||
|
check(resourcePolicy, failRes(resource), resource);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Policies validation - Statement::Action_block/' +
|
const actionTests = [
|
||||||
|
{
|
||||||
|
name: 'should succeed for foo:bar',
|
||||||
|
value: 'foo:bar',
|
||||||
|
expected: successRes,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'should succeed for foo:*',
|
||||||
|
value: 'foo:*',
|
||||||
|
expected: successRes,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'should succeed for *',
|
||||||
|
value: '*',
|
||||||
|
expected: successRes,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'should fail for **',
|
||||||
|
value: '**',
|
||||||
|
expected: 'fail',
|
||||||
|
errMessage: errDict.pattern.Action,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'should fail for foobar',
|
||||||
|
value: 'foobar',
|
||||||
|
expected: 'fail',
|
||||||
|
errMessage: errDict.pattern.Action,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
describe('User policies validation - Statement::Action_block/' +
|
||||||
'Statement::NotAction_block', () => {
|
'Statement::NotAction_block', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
policy.Statement.Action = undefined;
|
userPolicy.Statement.Action = undefined;
|
||||||
policy.Statement.NotAction = undefined;
|
userPolicy.Statement.NotAction = undefined;
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should succeed for foo:bar', () => {
|
actionTests.forEach(test => {
|
||||||
policy.Statement.Action = 'foo:bar';
|
it(`${test.name}`, () => {
|
||||||
check(policy, successRes);
|
userPolicy.Statement.Action = test.value;
|
||||||
|
if (test.expected === 'fail') {
|
||||||
|
check(userPolicy, failRes(user, test.errMessage), user);
|
||||||
|
} else {
|
||||||
|
check(userPolicy, test.expected, user);
|
||||||
|
}
|
||||||
|
|
||||||
policy.Statement.Action = undefined;
|
userPolicy.Statement.Action = undefined;
|
||||||
policy.Statement.NotAction = 'foo:bar';
|
userPolicy.Statement.NotAction = test.value;
|
||||||
check(policy, successRes);
|
if (test.expected === 'fail') {
|
||||||
|
check(userPolicy, failRes(user, test.errMessage), user);
|
||||||
|
} else {
|
||||||
|
check(userPolicy, test.expected, user);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should succeed for foo:*', () => {
|
|
||||||
policy.Statement.Action = 'foo:*';
|
|
||||||
check(policy, successRes);
|
|
||||||
|
|
||||||
policy.Statement.Action = undefined;
|
|
||||||
policy.Statement.NotAction = 'foo:*';
|
|
||||||
check(policy, successRes);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should succeed for *', () => {
|
|
||||||
policy.Statement.Action = '*';
|
|
||||||
check(policy, successRes);
|
|
||||||
|
|
||||||
policy.Statement.Action = undefined;
|
|
||||||
policy.Statement.NotAction = '*';
|
|
||||||
check(policy, successRes);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should fail for **', () => {
|
|
||||||
policy.Statement.Action = '**';
|
|
||||||
check(policy, failRes(errDict.pattern.Action));
|
|
||||||
|
|
||||||
policy.Statement.Action = undefined;
|
|
||||||
policy.Statement.NotAction = '**';
|
|
||||||
check(policy, failRes(errDict.pattern.Action));
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should fail for foobar', () => {
|
|
||||||
policy.Statement.Action = 'foobar';
|
|
||||||
check(policy, failRes(errDict.pattern.Action));
|
|
||||||
|
|
||||||
policy.Statement.Action = undefined;
|
|
||||||
policy.Statement.NotAction = 'foobar';
|
|
||||||
check(policy, failRes(errDict.pattern.Action));
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Policies validation - Statement::Resource_block' +
|
describe('Resource policies validation - Statement::Action_block', () => {
|
||||||
|
actionTests.forEach(test => {
|
||||||
|
it(`${test.name}`, () => {
|
||||||
|
resourcePolicy.Statement[0].Action = test.value;
|
||||||
|
if (test.expected === 'fail') {
|
||||||
|
check(resourcePolicy, failRes(resource, test.errMessage),
|
||||||
|
resource);
|
||||||
|
} else {
|
||||||
|
check(resourcePolicy, test.expected, resource);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
const resourceTests = [
|
||||||
|
{
|
||||||
|
name: 'should succeed for arn:aws::s3:::*',
|
||||||
|
value: 'arn:aws:s3:::*',
|
||||||
|
expected: successRes,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'should succeed for arn:aws:s3:::test/home/${aws:username}',
|
||||||
|
value: 'arn:aws:s3:::test/home/${aws:username}',
|
||||||
|
expected: successRes,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'should succeed for arn:aws:ec2:us-west-1:1234567890:vol/*',
|
||||||
|
value: 'arn:aws:ec2:us-west-1:1234567890:vol/*',
|
||||||
|
expected: successRes,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'should succeed for *',
|
||||||
|
value: '*',
|
||||||
|
expected: successRes,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'should fail for arn:aws:ec2:us-west-1:vol/* - missing region',
|
||||||
|
value: 'arn:aws:ec2:us-west-1:vol/*',
|
||||||
|
expected: 'fail',
|
||||||
|
errMessage: errDict.pattern.Resource,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'should fail for arn:aws:ec2:us-west-1:123456789:v/${} - ${}',
|
||||||
|
value: 'arn:aws:ec2:us-west-1:123456789:v/${}',
|
||||||
|
expected: 'fail',
|
||||||
|
errMessage: errDict.pattern.Resource,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'should fail for ec2:us-west-1:qwerty:vol/* - missing arn:aws:',
|
||||||
|
value: 'ec2:us-west-1:123456789012:vol/*',
|
||||||
|
expected: 'fail',
|
||||||
|
errMessage: errDict.pattern.Resource,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
describe('User policies validation - Statement::Resource_block' +
|
||||||
'Statement::NotResource_block', () => {
|
'Statement::NotResource_block', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
policy.Statement.Resource = undefined;
|
userPolicy.Statement.Resource = undefined;
|
||||||
policy.Statement.NotResource = undefined;
|
userPolicy.Statement.NotResource = undefined;
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should succeed for arn:aws:s3:::*', () => {
|
resourceTests.forEach(test => {
|
||||||
policy.Statement.Resource = 'arn:aws:s3:::*';
|
it(`${test.name}`, () => {
|
||||||
check(policy, successRes);
|
userPolicy.Statement.Resource = test.value;
|
||||||
|
if (test.expected === 'fail') {
|
||||||
|
check(userPolicy, failRes(user, test.errMessage), user);
|
||||||
|
} else {
|
||||||
|
check(userPolicy, test.expected, user);
|
||||||
|
}
|
||||||
|
|
||||||
policy.Statement.Resource = undefined;
|
userPolicy.Statement.Resource = undefined;
|
||||||
policy.Statement.NotResource = 'arn:aws:s3:::*';
|
userPolicy.Statement.NotResource = test.value;
|
||||||
check(policy, successRes);
|
if (test.expected === 'fail') {
|
||||||
|
check(userPolicy, failRes(user, test.errMessage), user);
|
||||||
|
} else {
|
||||||
|
check(userPolicy, test.expected, user);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should succeed for arn:aws:s3:::test/home/${aws:username}', () => {
|
|
||||||
policy.Statement.Resource = 'arn:aws:s3:::test/home/${aws:username}';
|
|
||||||
check(policy, successRes);
|
|
||||||
|
|
||||||
policy.Statement.Resource = undefined;
|
|
||||||
policy.Statement.NotResource = 'arn:aws:s3:::test/home/${aws:username}';
|
|
||||||
check(policy, successRes);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should succeed for arn:aws:ec2:us-west-1:1234567890:vol/*', () => {
|
|
||||||
policy.Statement.Resource = 'arn:aws:ec2:us-west-1:1234567890:vol/*';
|
|
||||||
check(policy, successRes);
|
|
||||||
|
|
||||||
policy.Statement.Resource = undefined;
|
|
||||||
policy.Statement.NotResource = 'arn:aws:ec2:us-west-1:1234567890:vol/*';
|
|
||||||
check(policy, successRes);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should succeed for *', () => {
|
|
||||||
policy.Statement.Resource = '*';
|
|
||||||
check(policy, successRes);
|
|
||||||
|
|
||||||
policy.Statement.Resource = undefined;
|
|
||||||
policy.Statement.NotResource = '*';
|
|
||||||
check(policy, successRes);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should fail for arn:aws:ec2:us-west-1:vol/* - missing region', () => {
|
|
||||||
policy.Statement.Resource = 'arn:aws:ec2:1234567890:vol/*';
|
|
||||||
check(policy, failRes(errDict.pattern.Resource));
|
|
||||||
|
|
||||||
policy.Statement.Resource = undefined;
|
|
||||||
policy.Statement.NotResource = 'arn:aws:ec2:1234567890:vol/*';
|
|
||||||
check(policy, failRes(errDict.pattern.Resource));
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should fail for arn:aws:ec2:us-west-1:123456789:v/${} - ${}', () => {
|
|
||||||
policy.Statement.Resource = 'arn:aws:ec2:us-west-1:123456789:v/${}';
|
|
||||||
check(policy, failRes(errDict.pattern.Resource));
|
|
||||||
|
|
||||||
policy.Statement.Resource = undefined;
|
|
||||||
policy.Statement.NotResource = 'arn:aws:ec2:us-west-1:123456789:v/${}';
|
|
||||||
check(policy, failRes(errDict.pattern.Resource));
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should fail for ec2:us-west-1:qwerty:vol/* - missing arn:aws:', () => {
|
|
||||||
policy.Statement.Resource = 'ec2:us-west-1:123456789012:vol/*';
|
|
||||||
check(policy, failRes(errDict.pattern.Resource));
|
|
||||||
|
|
||||||
policy.Statement.Resource = undefined;
|
|
||||||
policy.Statement.NotResource = 'ec2:us-west-1:123456789012:vol/*';
|
|
||||||
check(policy, failRes(errDict.pattern.Resource));
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should fail for empty list of resources', () => {
|
it('should fail for empty list of resources', () => {
|
||||||
policy.Statement.Resource = [];
|
userPolicy.Statement.Resource = [];
|
||||||
check(policy, failRes(errDict.minItems.Resource));
|
check(userPolicy, failRes(user, errDict.minItems.Resource), user);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Resource policies validation - Statement::Resource_block', () => {
|
||||||
|
resourceTests.forEach(test => {
|
||||||
|
it(`${test.name}`, () => {
|
||||||
|
resourcePolicy.Statement[0].Resource = test.value;
|
||||||
|
if (test.expected === 'fail') {
|
||||||
|
check(resourcePolicy, failRes(resource, test.errMessage),
|
||||||
|
resource);
|
||||||
|
} else {
|
||||||
|
check(resourcePolicy, test.expected, resource);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should fail for empty list of resources', () => {
|
||||||
|
resourcePolicy.Statement[0].Resource = [];
|
||||||
|
check(resourcePolicy, failRes(resource, errDict.minItems.Resource),
|
||||||
|
resource);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Policies validation - Statement::Condition_block', () => {
|
describe('Policies validation - Statement::Condition_block', () => {
|
||||||
it('should succeed for single Condition', () => {
|
it('user policy should succeed for single Condition', () => {
|
||||||
check(policy, successRes);
|
check(userPolicy, successRes, user);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should succeed for multiple Conditions', () => {
|
it('resource policy should succeed for single Condition', () => {
|
||||||
policy.Statement.Condition = {
|
check(resourcePolicy, successRes, resource);
|
||||||
|
});
|
||||||
|
|
||||||
|
[
|
||||||
|
{
|
||||||
|
name: 'should succeed for multiple Conditions',
|
||||||
|
value: {
|
||||||
StringNotLike: { 's3:prefix': ['Development/*'] },
|
StringNotLike: { 's3:prefix': ['Development/*'] },
|
||||||
Null: { 's3:prefix': false },
|
Null: { 's3:prefix': false },
|
||||||
};
|
},
|
||||||
check(policy, successRes);
|
expected: successRes,
|
||||||
});
|
},
|
||||||
|
{
|
||||||
it('should fail when Condition is not an Object', () => {
|
name: 'should fail when Condition is not an Object',
|
||||||
policy.Statement.Condition = 'NumericLessThanEquals';
|
value: 'NumericLessThanEquals',
|
||||||
check(policy, failRes());
|
expected: 'fail',
|
||||||
});
|
},
|
||||||
|
{
|
||||||
it('should fail for an invalid Condition', () => {
|
name: 'should fail for an invalid Condition',
|
||||||
policy.Statement.Condition = {
|
value: {
|
||||||
SomethingLike: { 's3:prefix': ['Development/*'] },
|
SomethingLike: { 's3:prefix': ['Development/*'] },
|
||||||
};
|
},
|
||||||
check(policy, failRes());
|
expected: 'fail',
|
||||||
});
|
},
|
||||||
|
{
|
||||||
it('should fail when one of the multiple conditions is invalid', () => {
|
name: 'should fail when one of the multiple conditions is invalid',
|
||||||
policy.Statement.Condition = {
|
value: {
|
||||||
Null: { 's3:prefix': false },
|
Null: { 's3:prefix': false },
|
||||||
SomethingLike: { 's3:prefix': ['Development/*'] },
|
SomethingLike: { 's3:prefix': ['Development/*'] },
|
||||||
};
|
},
|
||||||
check(policy, failRes());
|
expected: 'fail',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'should fail when invalid property is assigned',
|
||||||
|
value: {
|
||||||
|
SomethingLike: { 's3:prefix': ['Development/*'] },
|
||||||
|
},
|
||||||
|
expected: 'fail',
|
||||||
|
},
|
||||||
|
].forEach(test => {
|
||||||
|
it(`user policy ${test.name}`, () => {
|
||||||
|
userPolicy.Statement.Condition = test.value;
|
||||||
|
if (test.expected === 'fail') {
|
||||||
|
check(userPolicy, failRes(user), user);
|
||||||
|
} else {
|
||||||
|
check(userPolicy, test.expected, user);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should fail when invalid property is assigned', () => {
|
it(`resource policy ${test.name}`, () => {
|
||||||
policy.Condition = {
|
resourcePolicy.Statement[0].Condition = test.value;
|
||||||
SomethingLike: { 's3:prefix': ['Development/*'] },
|
if (test.expected === 'fail') {
|
||||||
};
|
check(resourcePolicy, failRes(resource), resource);
|
||||||
check(policy, failRes());
|
} else {
|
||||||
|
check(resourcePolicy, test.expected, resource);
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue