frostfs-s3-gw/pkg/bucket/policy/condition/func_test.go

353 lines
10 KiB
Go

/*
* MinIO Cloud Storage, (C) 2018 MinIO, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package condition
import (
"encoding/json"
"reflect"
"testing"
)
func TestFunctionsEvaluate(t *testing.T) {
func1, err := newNullFunc(S3XAmzCopySource, NewValueSet(NewBoolValue(true)))
if err != nil {
t.Fatalf("unexpected error. %v\n", err)
}
func2, err := newIPAddressFunc(AWSSourceIP, NewValueSet(NewStringValue("192.168.1.0/24")))
if err != nil {
t.Fatalf("unexpected error. %v\n", err)
}
func3, err := newStringEqualsFunc(S3XAmzCopySource, NewValueSet(NewStringValue("mybucket/myobject")))
if err != nil {
t.Fatalf("unexpected error. %v\n", err)
}
func4, err := newStringLikeFunc(S3XAmzCopySource, NewValueSet(NewStringValue("mybucket/myobject*")))
if err != nil {
t.Fatalf("unexpected error. %v\n", err)
}
case1Function := NewFunctions(func1, func2, func3, func4)
testCases := []struct {
functions Functions
values map[string][]string
expectedResult bool
}{
{case1Function, map[string][]string{
"x-amz-copy-source": {"mybucket/myobject"},
"SourceIp": {"192.168.1.10"},
}, false},
{case1Function, map[string][]string{
"x-amz-copy-source": {"mybucket/myobject"},
"SourceIp": {"192.168.1.10"},
"Refer": {"http://example.org/"},
}, false},
{case1Function, map[string][]string{"x-amz-copy-source": {"mybucket/myobject"}}, false},
{case1Function, map[string][]string{"SourceIp": {"192.168.1.10"}}, false},
{case1Function, map[string][]string{
"x-amz-copy-source": {"mybucket/yourobject"},
"SourceIp": {"192.168.1.10"},
}, false},
{case1Function, map[string][]string{
"x-amz-copy-source": {"mybucket/myobject"},
"SourceIp": {"192.168.2.10"},
}, false},
{case1Function, map[string][]string{
"x-amz-copy-source": {"mybucket/myobject"},
"Refer": {"http://example.org/"},
}, false},
}
for i, testCase := range testCases {
result := testCase.functions.Evaluate(testCase.values)
if result != testCase.expectedResult {
t.Errorf("case %v: expected: %v, got: %v\n", i+1, testCase.expectedResult, result)
}
}
}
func TestFunctionsKeys(t *testing.T) {
func1, err := newNullFunc(S3XAmzCopySource, NewValueSet(NewBoolValue(true)))
if err != nil {
t.Fatalf("unexpected error. %v\n", err)
}
func2, err := newIPAddressFunc(AWSSourceIP, NewValueSet(NewStringValue("192.168.1.0/24")))
if err != nil {
t.Fatalf("unexpected error. %v\n", err)
}
func3, err := newStringEqualsFunc(S3XAmzCopySource, NewValueSet(NewStringValue("mybucket/myobject")))
if err != nil {
t.Fatalf("unexpected error. %v\n", err)
}
func4, err := newStringLikeFunc(S3XAmzCopySource, NewValueSet(NewStringValue("mybucket/myobject*")))
if err != nil {
t.Fatalf("unexpected error. %v\n", err)
}
testCases := []struct {
functions Functions
expectedResult KeySet
}{
{NewFunctions(func1, func2, func3, func4), NewKeySet(S3XAmzCopySource, AWSSourceIP)},
}
for i, testCase := range testCases {
result := testCase.functions.Keys()
if !reflect.DeepEqual(result, testCase.expectedResult) {
t.Fatalf("case %v: expected: %v, got: %v\n", i+1, testCase.expectedResult, result)
}
}
}
func TestFunctionsMarshalJSON(t *testing.T) {
func1, err := newStringLikeFunc(S3XAmzMetadataDirective, NewValueSet(NewStringValue("REPL*")))
if err != nil {
t.Fatalf("unexpected error. %v\n", err)
}
func2, err := newStringEqualsFunc(S3XAmzCopySource, NewValueSet(NewStringValue("mybucket/myobject")))
if err != nil {
t.Fatalf("unexpected error. %v\n", err)
}
func3, err := newStringNotEqualsFunc(S3XAmzServerSideEncryption, NewValueSet(NewStringValue("AES256")))
if err != nil {
t.Fatalf("unexpected error. %v\n", err)
}
func4, err := newNotIPAddressFunc(AWSSourceIP,
NewValueSet(NewStringValue("10.1.10.0/24")))
if err != nil {
t.Fatalf("unexpected error. %v\n", err)
}
func5, err := newStringNotLikeFunc(S3XAmzStorageClass, NewValueSet(NewStringValue("STANDARD")))
if err != nil {
t.Fatalf("unexpected error. %v\n", err)
}
func6, err := newNullFunc(S3XAmzServerSideEncryptionCustomerAlgorithm, NewValueSet(NewBoolValue(true)))
if err != nil {
t.Fatalf("unexpected error. %v\n", err)
}
func7, err := newIPAddressFunc(AWSSourceIP,
NewValueSet(NewStringValue("192.168.1.0/24")))
if err != nil {
t.Fatalf("unexpected error. %v\n", err)
}
case1Result := []byte(`{"IpAddress":{"aws:SourceIp":["192.168.1.0/24"]},"NotIpAddress":{"aws:SourceIp":["10.1.10.0/24"]},"Null":{"s3:x-amz-server-side-encryption-customer-algorithm":[true]},"StringEquals":{"s3:x-amz-copy-source":["mybucket/myobject"]},"StringLike":{"s3:x-amz-metadata-directive":["REPL*"]},"StringNotEquals":{"s3:x-amz-server-side-encryption":["AES256"]},"StringNotLike":{"s3:x-amz-storage-class":["STANDARD"]}}`)
case2Result := []byte(`{"Null":{"s3:x-amz-server-side-encryption-customer-algorithm":[true]}}`)
testCases := []struct {
functions Functions
expectedResult []byte
expectErr bool
}{
{NewFunctions(func1, func2, func3, func4, func5, func6, func7), case1Result, false},
{NewFunctions(func6), case2Result, false},
{NewFunctions(), []byte(`{}`), false},
{nil, []byte(`{}`), false},
}
for i, testCase := range testCases {
result, err := json.Marshal(testCase.functions)
expectErr := (err != nil)
if testCase.expectErr != expectErr {
t.Fatalf("case %v: error: expected: %v, got: %v", i+1, testCase.expectErr, expectErr)
}
if !testCase.expectErr {
if !reflect.DeepEqual(result, testCase.expectedResult) {
t.Fatalf("case %v: result: expected: %v, got: %v", i+1, string(testCase.expectedResult), string(result))
}
}
}
}
func TestFunctionsUnmarshalJSON(t *testing.T) {
case1Data := []byte(`{
"StringLike": {
"s3:x-amz-metadata-directive": "REPL*"
},
"StringEquals": {
"s3:x-amz-copy-source": "mybucket/myobject"
},
"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"
]
}
}`)
func1, err := newStringLikeFunc(S3XAmzMetadataDirective, NewValueSet(NewStringValue("REPL*")))
if err != nil {
t.Fatalf("unexpected error. %v\n", err)
}
func2, err := newStringEqualsFunc(S3XAmzCopySource, NewValueSet(NewStringValue("mybucket/myobject")))
if err != nil {
t.Fatalf("unexpected error. %v\n", err)
}
func3, err := newStringNotEqualsFunc(S3XAmzServerSideEncryption, NewValueSet(NewStringValue("AES256")))
if err != nil {
t.Fatalf("unexpected error. %v\n", err)
}
func4, err := newNotIPAddressFunc(AWSSourceIP,
NewValueSet(NewStringValue("10.1.10.0/24"), NewStringValue("10.10.1.0/24")))
if err != nil {
t.Fatalf("unexpected error. %v\n", err)
}
func5, err := newStringNotLikeFunc(S3XAmzStorageClass, NewValueSet(NewStringValue("STANDARD")))
if err != nil {
t.Fatalf("unexpected error. %v\n", err)
}
func6, err := newNullFunc(S3XAmzServerSideEncryptionCustomerAlgorithm, NewValueSet(NewBoolValue(true)))
if err != nil {
t.Fatalf("unexpected error. %v\n", err)
}
func7, err := newIPAddressFunc(AWSSourceIP,
NewValueSet(NewStringValue("192.168.1.0/24"), NewStringValue("192.168.2.0/24")))
if err != nil {
t.Fatalf("unexpected error. %v\n", err)
}
case2Data := []byte(`{
"Null": {
"s3:x-amz-server-side-encryption-customer-algorithm": true
},
"Null": {
"s3:x-amz-server-side-encryption-customer-algorithm": "true"
}
}`)
case3Data := []byte(`{}`)
case4Data := []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 conditions, success case only one value is preserved.
{case2Data, NewFunctions(func6), false},
// empty condition error.
{case3Data, nil, true},
// Success case multiple keys, same condition.
{case4Data, NewFunctions(func1, func2_1, func2_2, func2_3, func3, func4, func5, func6, func7), false},
}
for i, testCase := range testCases {
result := new(Functions)
err := json.Unmarshal(testCase.data, result)
expectErr := (err != nil)
if testCase.expectErr != expectErr {
t.Fatalf("case %v: error: expected: %v, got: %v", i+1, testCase.expectErr, expectErr)
}
if !testCase.expectErr {
if (*result).String() != testCase.expectedResult.String() {
t.Fatalf("case %v: result: expected: %v, got: %v", i+1, testCase.expectedResult, *result)
}
}
}
}