diff --git a/pkg/policy/condition/func.go b/pkg/policy/condition/func.go index 9ae7d311e..593f9edad 100644 --- a/pkg/policy/condition/func.go +++ b/pkg/policy/condition/func.go @@ -71,7 +71,13 @@ func (functions Functions) MarshalJSON() ([]byte, error) { nm := make(map[name]map[Key]ValueSet) for _, f := range functions { - nm[f.name()] = f.toMap() + if _, ok := nm[f.name()]; ok { + for k, v := range f.toMap() { + nm[f.name()][k] = v + } + } else { + nm[f.name()] = f.toMap() + } } return json.Marshal(nm) diff --git a/pkg/policy/condition/func_test.go b/pkg/policy/condition/func_test.go index a2ba9c47f..7c07e92a9 100644 --- a/pkg/policy/condition/func_test.go +++ b/pkg/policy/condition/func_test.go @@ -273,18 +273,73 @@ func TestFunctionsUnmarshalJSON(t *testing.T) { "DateEquals": { "aws:CurrentTime": "2013-06-30T00:00:00Z" } }`) + case5Data := []byte(`{ + "StringLike": { + "s3:x-amz-metadata-directive": "REPL*" + }, + "StringEquals": { + "s3:x-amz-copy-source": "mybucket/myobject", + "s3:prefix": [ + "", + "home/" + ], + "s3:delimiter": [ + "/" + ] + }, + "StringNotEquals": { + "s3:x-amz-server-side-encryption": "AES256" + }, + "NotIpAddress": { + "aws:SourceIp": [ + "10.1.10.0/24", + "10.10.1.0/24" + ] + }, + "StringNotLike": { + "s3:x-amz-storage-class": "STANDARD" + }, + "Null": { + "s3:x-amz-server-side-encryption-customer-algorithm": true + }, + "IpAddress": { + "aws:SourceIp": [ + "192.168.1.0/24", + "192.168.2.0/24" + ] + } +}`) + + func2_1, err := newStringEqualsFunc(S3XAmzCopySource, NewValueSet(NewStringValue("mybucket/myobject"))) + if err != nil { + t.Fatalf("unexpected error. %v\n", err) + } + + func2_2, err := newStringEqualsFunc(S3Prefix, NewValueSet(NewStringValue(""), NewStringValue("home/"))) + if err != nil { + t.Fatalf("unexpected error. %v\n", err) + } + + func2_3, err := newStringEqualsFunc(S3Delimiter, NewValueSet(NewStringValue("/"))) + if err != nil { + t.Fatalf("unexpected error. %v\n", err) + } + testCases := []struct { data []byte expectedResult Functions expectErr bool }{ + // Success case, basic conditions. {case1Data, NewFunctions(func1, func2, func3, func4, func5, func6, func7), false}, - // duplicate condition error. + // Duplicate conditions, success case only one value is preserved. {case2Data, NewFunctions(func6), false}, // empty condition error. {case3Data, nil, true}, // unsupported condition error. {case4Data, nil, true}, + // Success case multiple keys, same condition. + {case5Data, NewFunctions(func1, func2_1, func2_2, func2_3, func3, func4, func5, func6, func7), false}, } for i, testCase := range testCases {