|
|
/* * Minio Cloud Storage, (C) 2015, 2016 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 cmd
import ( "bytes" "encoding/json" "errors" "fmt" "testing"
"github.com/minio/minio-go/pkg/set" )
// Common bucket actions for both read and write policies.
var ( readWriteBucketActions = []string{ "s3:GetBucketLocation", "s3:ListBucket", "s3:ListBucketMultipartUploads", // Add more bucket level read-write actions here.
} readWriteObjectActions = []string{ "s3:AbortMultipartUpload", "s3:DeleteObject", "s3:GetObject", "s3:ListMultipartUploadParts", "s3:PutObject", // Add more object level read-write actions here.
} )
// Write only actions.
var ( writeOnlyBucketActions = []string{ "s3:GetBucketLocation", "s3:ListBucketMultipartUploads", // Add more bucket level write actions here.
} writeOnlyObjectActions = []string{ "s3:AbortMultipartUpload", "s3:DeleteObject", "s3:ListMultipartUploadParts", "s3:PutObject", // Add more object level write actions here.
} )
// Read only actions.
var ( readOnlyBucketActions = []string{ "s3:GetBucketLocation", "s3:ListBucket", // Add more bucket level read actions here.
} readOnlyObjectActions = []string{ "s3:GetObject", // Add more object level read actions here.
} )
// Obtain bucket statement for read-write bucketPolicy.
func getReadWriteObjectStatement(bucketName, objectPrefix string) policyStatement { objectResourceStatement := policyStatement{} objectResourceStatement.Effect = "Allow" objectResourceStatement.Principal = map[string]interface{}{ "AWS": "*", } objectResourceStatement.Resources = set.CreateStringSet([]string{fmt.Sprintf("%s%s", AWSResourcePrefix, bucketName+"/"+objectPrefix+"*")}...) objectResourceStatement.Actions = set.CreateStringSet(readWriteObjectActions...) return objectResourceStatement }
// Obtain object statement for read-write bucketPolicy.
func getReadWriteBucketStatement(bucketName, objectPrefix string) policyStatement { bucketResourceStatement := policyStatement{} bucketResourceStatement.Effect = "Allow" bucketResourceStatement.Principal = map[string]interface{}{ "AWS": "*", } bucketResourceStatement.Resources = set.CreateStringSet([]string{fmt.Sprintf("%s%s", AWSResourcePrefix, bucketName)}...) bucketResourceStatement.Actions = set.CreateStringSet(readWriteBucketActions...) return bucketResourceStatement }
// Obtain statements for read-write bucketPolicy.
func getReadWriteStatement(bucketName, objectPrefix string) []policyStatement { statements := []policyStatement{} // Save the read write policy.
statements = append(statements, getReadWriteBucketStatement(bucketName, objectPrefix), getReadWriteObjectStatement(bucketName, objectPrefix)) return statements }
// Obtain bucket statement for read only bucketPolicy.
func getReadOnlyBucketStatement(bucketName, objectPrefix string) policyStatement { bucketResourceStatement := policyStatement{} bucketResourceStatement.Effect = "Allow" bucketResourceStatement.Principal = map[string]interface{}{ "AWS": "*", } bucketResourceStatement.Resources = set.CreateStringSet([]string{fmt.Sprintf("%s%s", AWSResourcePrefix, bucketName)}...) bucketResourceStatement.Actions = set.CreateStringSet(readOnlyBucketActions...) return bucketResourceStatement }
// Obtain object statement for read only bucketPolicy.
func getReadOnlyObjectStatement(bucketName, objectPrefix string) policyStatement { objectResourceStatement := policyStatement{} objectResourceStatement.Effect = "Allow" objectResourceStatement.Principal = map[string]interface{}{ "AWS": "*", } objectResourceStatement.Resources = set.CreateStringSet([]string{fmt.Sprintf("%s%s", AWSResourcePrefix, bucketName+"/"+objectPrefix+"*")}...) objectResourceStatement.Actions = set.CreateStringSet(readOnlyObjectActions...) return objectResourceStatement }
// Obtain statements for read only bucketPolicy.
func getReadOnlyStatement(bucketName, objectPrefix string) []policyStatement { statements := []policyStatement{} // Save the read only policy.
statements = append(statements, getReadOnlyBucketStatement(bucketName, objectPrefix), getReadOnlyObjectStatement(bucketName, objectPrefix)) return statements }
// Obtain bucket statements for write only bucketPolicy.
func getWriteOnlyBucketStatement(bucketName, objectPrefix string) policyStatement {
bucketResourceStatement := policyStatement{} bucketResourceStatement.Effect = "Allow" bucketResourceStatement.Principal = map[string]interface{}{ "AWS": "*", } bucketResourceStatement.Resources = set.CreateStringSet([]string{fmt.Sprintf("%s%s", AWSResourcePrefix, bucketName)}...) bucketResourceStatement.Actions = set.CreateStringSet(writeOnlyBucketActions...) return bucketResourceStatement }
// Obtain object statements for write only bucketPolicy.
func getWriteOnlyObjectStatement(bucketName, objectPrefix string) policyStatement { objectResourceStatement := policyStatement{} objectResourceStatement.Effect = "Allow" objectResourceStatement.Principal = map[string]interface{}{ "AWS": "*", } objectResourceStatement.Resources = set.CreateStringSet([]string{fmt.Sprintf("%s%s", AWSResourcePrefix, bucketName+"/"+objectPrefix+"*")}...) objectResourceStatement.Actions = set.CreateStringSet(writeOnlyObjectActions...) return objectResourceStatement }
// Obtain statements for write only bucketPolicy.
func getWriteOnlyStatement(bucketName, objectPrefix string) []policyStatement { statements := []policyStatement{} // Write only policy.
// Save the write only policy.
statements = append(statements, getWriteOnlyBucketStatement(bucketName, objectPrefix), getWriteOnlyBucketStatement(bucketName, objectPrefix)) return statements }
// Tests validate Action validator.
func TestIsValidActions(t *testing.T) { testCases := []struct { // input.
actions set.StringSet // expected output.
err error // flag indicating whether the test should pass.
shouldPass bool }{ // Inputs with unsupported Action.
// Test case - 1.
// "s3:ListObject" is an invalid Action.
{set.CreateStringSet([]string{"s3:GetObject", "s3:ListObject", "s3:RemoveObject"}...), errors.New("Unsupported actions found: ‘set.StringSet{\"s3:RemoveObject\":struct {}{}, \"s3:ListObject\":struct {}{}}’, please validate your policy document."), false}, // Test case - 2.
// Empty Actions.
{set.CreateStringSet([]string{}...), errors.New("Action list cannot be empty."), false}, // Test case - 3.
// "s3:DeleteEverything"" is an invalid Action.
{set.CreateStringSet([]string{"s3:GetObject", "s3:ListBucket", "s3:PutObject", "s3:DeleteEverything"}...), errors.New("Unsupported actions found: ‘set.StringSet{\"s3:DeleteEverything\":struct {}{}}’, please validate your policy document."), false}, // Inputs with valid Action.
// Test Case - 4.
{set.CreateStringSet([]string{ "s3:*", "*", "s3:GetObject", "s3:ListBucket", "s3:PutObject", "s3:GetBucketLocation", "s3:DeleteObject", "s3:AbortMultipartUpload", "s3:ListBucketMultipartUploads", "s3:ListMultipartUploadParts"}...), nil, true}, } for i, testCase := range testCases { err := isValidActions(testCase.actions) if err != nil && testCase.shouldPass { t.Errorf("Test %d: Expected to pass, but failed with: <ERROR> %s", i+1, err.Error()) } if err == nil && !testCase.shouldPass { t.Errorf("Test %d: Expected to fail with <ERROR> \"%s\", but passed instead", i+1, testCase.err.Error()) } } }
// Tests validate Effect validator.
func TestIsValidEffect(t *testing.T) { testCases := []struct { // input.
effect string // expected output.
err error // flag indicating whether the test should pass.
shouldPass bool }{ // Inputs with unsupported Effect.
// Test case - 1.
{"", errors.New("Policy effect cannot be empty."), false}, // Test case - 2.
{"DontAllow", errors.New("Unsupported Effect found: ‘DontAllow’, please validate your policy document."), false}, // Test case - 3.
{"NeverAllow", errors.New("Unsupported Effect found: ‘NeverAllow’, please validate your policy document."), false}, // Test case - 4.
{"AllowAlways", errors.New("Unsupported Effect found: ‘AllowAlways’, please validate your policy document."), false},
// Inputs with valid Effect.
// Test Case - 5.
{"Allow", nil, true}, // Test Case - 6.
{"Deny", nil, true}, } for i, testCase := range testCases { err := isValidEffect(testCase.effect) if err != nil && testCase.shouldPass { t.Errorf("Test %d: Expected to pass, but failed with: <ERROR> %s", i+1, err.Error()) } if err == nil && !testCase.shouldPass { t.Errorf("Test %d: Expected to fail with <ERROR> \"%s\", but passed instead", i+1, testCase.err.Error()) } // Failed as expected, but does it fail for the expected reason.
if err != nil && !testCase.shouldPass { if err.Error() != testCase.err.Error() { t.Errorf("Test %d: Expected to fail with error \"%s\", but instead failed with error \"%s\"", i+1, testCase.err.Error(), err.Error()) } } } }
// Tests validate Resources validator.
func TestIsValidResources(t *testing.T) { testCases := []struct { // input.
resources []string // expected output.
err error // flag indicating whether the test should pass.
shouldPass bool }{ // Inputs with unsupported Action.
// Test case - 1.
// Empty Resources.
{[]string{}, errors.New("Resource list cannot be empty."), false}, // Test case - 2.
// A valid resource should have prefix "arn:aws:s3:::".
{[]string{"my-resource"}, errors.New("Unsupported resource style found: ‘my-resource’, please validate your policy document."), false}, // Test case - 3.
// A Valid resource should have bucket name followed by "arn:aws:s3:::".
{[]string{"arn:aws:s3:::"}, errors.New("Invalid resource style found: ‘arn:aws:s3:::’, please validate your policy document."), false}, // Test Case - 4.
// Valid resource shouldn't have slash('/') followed by "arn:aws:s3:::".
{[]string{"arn:aws:s3:::/"}, errors.New("Invalid resource style found: ‘arn:aws:s3:::/’, please validate your policy document."), false},
// Test cases with valid Resources.
{[]string{"arn:aws:s3:::my-bucket"}, nil, true}, {[]string{"arn:aws:s3:::my-bucket/Asia/*"}, nil, true}, {[]string{"arn:aws:s3:::my-bucket/Asia/India/*"}, nil, true}, } for i, testCase := range testCases { err := isValidResources(set.CreateStringSet(testCase.resources...)) if err != nil && testCase.shouldPass { t.Errorf("Test %d: Expected to pass, but failed with: <ERROR> %s", i+1, err.Error()) } if err == nil && !testCase.shouldPass { t.Errorf("Test %d: Expected to fail with <ERROR> \"%s\", but passed instead", i+1, testCase.err.Error()) } // Failed as expected, but does it fail for the expected reason.
if err != nil && !testCase.shouldPass { if err.Error() != testCase.err.Error() { t.Errorf("Test %d: Expected to fail with error \"%s\", but instead failed with error \"%s\"", i+1, testCase.err.Error(), err.Error()) } } } }
// Tests validate principals validator.
func TestIsValidPrincipals(t *testing.T) { testCases := []struct { // input.
principals []string // expected output.
err error // flag indicating whether the test should pass.
shouldPass bool }{ // Inputs with unsupported Principals.
// Test case - 1.
// Empty Principals list.
{[]string{}, errors.New("Principal cannot be empty."), false}, // Test case - 2.
// "*" is the only valid principal.
{[]string{"my-principal"}, errors.New("Unsupported principals found: ‘set.StringSet{\"my-principal\":struct {}{}}’, please validate your policy document."), false}, // Test case - 3.
{[]string{"*", "111122233"}, errors.New("Unsupported principals found: ‘set.StringSet{\"111122233\":struct {}{}}’, please validate your policy document."), false}, // Test case - 4.
// Test case with valid principal value.
{[]string{"*"}, nil, true}, } for i, testCase := range testCases { err := isValidPrincipals(map[string]interface{}{ "AWS": testCase.principals, }) if err != nil && testCase.shouldPass { t.Errorf("Test %d: Expected to pass, but failed with: <ERROR> %s", i+1, err.Error()) } if err == nil && !testCase.shouldPass { t.Errorf("Test %d: Expected to fail with <ERROR> \"%s\", but passed instead", i+1, testCase.err.Error()) } // Failed as expected, but does it fail for the expected reason.
if err != nil && !testCase.shouldPass { if err.Error() != testCase.err.Error() { t.Errorf("Test %d: Expected to fail with error \"%s\", but instead failed with error \"%s\"", i+1, testCase.err.Error(), err.Error()) } } } }
// Tests validate policyStatement condition validator.
func TestIsValidConditions(t *testing.T) { // returns empty conditions map.
setEmptyConditions := func() map[string]map[string]set.StringSet { return make(map[string]map[string]set.StringSet) }
// returns map with the "StringEquals" set to empty map.
setEmptyStringEquals := func() map[string]map[string]set.StringSet { emptyMap := make(map[string]set.StringSet) conditions := make(map[string]map[string]set.StringSet) conditions["StringEquals"] = emptyMap return conditions
}
// returns map with the "StringNotEquals" set to empty map.
setEmptyStringNotEquals := func() map[string]map[string]set.StringSet { emptyMap := make(map[string]set.StringSet) conditions := make(map[string]map[string]set.StringSet) conditions["StringNotEquals"] = emptyMap return conditions
} // Generate conditions.
generateConditions := func(key1, key2, value string) map[string]map[string]set.StringSet { innerMap := make(map[string]set.StringSet) innerMap[key2] = set.CreateStringSet(value) conditions := make(map[string]map[string]set.StringSet) conditions[key1] = innerMap return conditions }
// generate ambigious conditions.
generateAmbigiousConditions := func() map[string]map[string]set.StringSet { innerMap := make(map[string]set.StringSet) innerMap["s3:prefix"] = set.CreateStringSet("Asia/") conditions := make(map[string]map[string]set.StringSet) conditions["StringEquals"] = innerMap conditions["StringNotEquals"] = innerMap return conditions }
// generate valid and non valid type in the condition map.
generateValidInvalidConditions := func() map[string]map[string]set.StringSet { innerMap := make(map[string]set.StringSet) innerMap["s3:prefix"] = set.CreateStringSet("Asia/") conditions := make(map[string]map[string]set.StringSet) conditions["StringEquals"] = innerMap conditions["InvalidType"] = innerMap return conditions }
// generate valid and invalid keys for valid types in the same condition map.
generateValidInvalidConditionKeys := func() map[string]map[string]set.StringSet { innerMapValid := make(map[string]set.StringSet) innerMapValid["s3:prefix"] = set.CreateStringSet("Asia/") innerMapInValid := make(map[string]set.StringSet) innerMapInValid["s3:invalid"] = set.CreateStringSet("Asia/") conditions := make(map[string]map[string]set.StringSet) conditions["StringEquals"] = innerMapValid conditions["StringEquals"] = innerMapInValid return conditions }
// List of Conditions used for test cases.
testConditions := []map[string]map[string]set.StringSet{ generateConditions("StringValues", "s3:max-keys", "100"), generateConditions("StringEquals", "s3:Object", "100"), generateAmbigiousConditions(), generateValidInvalidConditions(), generateValidInvalidConditionKeys(), setEmptyConditions(), setEmptyStringEquals(), setEmptyStringNotEquals(), generateConditions("StringEquals", "s3:prefix", "Asia/"), generateConditions("StringEquals", "s3:max-keys", "100"), generateConditions("StringNotEquals", "s3:prefix", "Asia/"), generateConditions("StringNotEquals", "s3:max-keys", "100"), }
testCases := []struct { inputCondition map[string]map[string]set.StringSet // expected result.
expectedErr error // flag indicating whether test should pass.
shouldPass bool }{ // Malformed conditions.
// Test case - 1.
// "StringValues" is an invalid type.
{testConditions[0], fmt.Errorf("Unsupported condition type 'StringValues', " + "please validate your policy document."), false}, // Test case - 2.
// "s3:Object" is an invalid key.
{testConditions[1], fmt.Errorf("Unsupported condition key " + "'StringEquals', please validate your policy document."), false}, // Test case - 3.
// Test case with Ambigious conditions set.
{testConditions[2], fmt.Errorf("Ambigious condition values for key 's3:prefix', " + "please validate your policy document."), false}, // Test case - 4.
// Test case with valid and invalid condition types.
{testConditions[3], fmt.Errorf("Unsupported condition type 'InvalidType', " + "please validate your policy document."), false}, // Test case - 5.
// Test case with valid and invalid condition keys.
{testConditions[4], fmt.Errorf("Unsupported condition key 'StringEquals', " + "please validate your policy document."), false}, // Test cases with valid conditions.
// Test case - 6.
{testConditions[5], nil, true}, // Test case - 7.
{testConditions[6], nil, true}, // Test case - 8.
{testConditions[7], nil, true}, // Test case - 9.
{testConditions[8], nil, true}, // Test case - 10.
{testConditions[9], nil, true}, // Test case - 11.
{testConditions[10], nil, true}, // Test case 10.
{testConditions[11], nil, true}, } for i, testCase := range testCases { actualErr := isValidConditions(testCase.inputCondition) if actualErr != nil && testCase.shouldPass { t.Errorf("Test %d: Expected to pass, but failed with: <ERROR> %s", i+1, actualErr.Error()) } if actualErr == nil && !testCase.shouldPass { t.Errorf("Test %d: Expected to fail with <ERROR> \"%s\", but passed instead", i+1, testCase.expectedErr.Error()) } // Failed as expected, but does it fail for the expected reason.
if actualErr != nil && !testCase.shouldPass { if actualErr.Error() != testCase.expectedErr.Error() { t.Errorf("Test %d: Expected to fail with error \"%s\", but instead failed with error \"%s\"", i+1, testCase.expectedErr.Error(), actualErr.Error()) } } } }
// Tests validate Policy Action and Resource fields.
func TestCheckbucketPolicyResources(t *testing.T) { // constructing policy statement without invalidPrefixActions (check bucket-policy-parser.go).
setValidPrefixActions := func(statements []policyStatement) []policyStatement { statements[0].Actions = set.CreateStringSet([]string{"s3:DeleteObject", "s3:PutObject"}...) return statements } // contracting policy statement with recursive resources.
// should result in ErrMalformedPolicy
setRecurseResource := func(statements []policyStatement) []policyStatement { statements[0].Resources = set.CreateStringSet([]string{"arn:aws:s3:::minio-bucket/Asia/*", "arn:aws:s3:::minio-bucket/Asia/India/*"}...) return statements }
// constructing policy statement with lexically close characters.
// should not result in ErrMalformedPolicy
setResourceLexical := func(statements []policyStatement) []policyStatement { statements[0].Resources = set.CreateStringSet([]string{"arn:aws:s3:::minio-bucket/op*", "arn:aws:s3:::minio-bucket/oo*"}...) return statements }
// List of bucketPolicy used for tests.
bucketAccessPolicies := []bucketPolicy{ // bucketPolicy - 1.
// Contains valid read only policy statement.
{Version: "1.0", Statements: getReadOnlyStatement("minio-bucket", "")}, // bucketPolicy - 2.
// Contains valid read-write only policy statement.
{Version: "1.0", Statements: getReadWriteStatement("minio-bucket", "Asia/")}, // bucketPolicy - 3.
// Contains valid write only policy statement.
{Version: "1.0", Statements: getWriteOnlyStatement("minio-bucket", "Asia/India/")}, // bucketPolicy - 4.
// Contains invalidPrefixActions.
// Since resourcePrefix is not to the bucket-name, it return ErrMalformedPolicy.
{Version: "1.0", Statements: getReadOnlyStatement("minio-bucket-fail", "Asia/India/")}, // bucketPolicy - 5.
// constructing policy statement without invalidPrefixActions (check bucket-policy-parser.go).
// but bucket part of the resource is not equal to the bucket name.
// this results in return of ErrMalformedPolicy.
{Version: "1.0", Statements: setValidPrefixActions(getWriteOnlyStatement("minio-bucket-fail", "Asia/India/"))}, // bucketPolicy - 6.
// contracting policy statement with recursive resources.
// should result in ErrMalformedPolicy
{Version: "1.0", Statements: setRecurseResource(setValidPrefixActions(getWriteOnlyStatement("minio-bucket", "")))}, // BucketPolciy - 7.
// constructing policy statement with non recursive but
// lexically close resources.
// should result in ErrNone.
{Version: "1.0", Statements: setResourceLexical(setValidPrefixActions(getWriteOnlyStatement("minio-bucket", "oo")))}, }
testCases := []struct { inputPolicy bucketPolicy // expected results.
apiErrCode APIErrorCode // Flag indicating whether the test should pass.
shouldPass bool }{ // Test case - 1.
{bucketAccessPolicies[0], ErrNone, true}, // Test case - 2.
{bucketAccessPolicies[1], ErrNone, true}, // Test case - 3.
{bucketAccessPolicies[2], ErrNone, true}, // Test case - 4.
// contains invalidPrefixActions (check bucket-policy-parser.go).
// Resource prefix will not be equal to the bucket name in this case.
{bucketAccessPolicies[3], ErrMalformedPolicy, false}, // Test case - 5.
// actions contain invalidPrefixActions (check bucket-policy-parser.go).
// Resource prefix bucket part is not equal to the bucket name in this case.
{bucketAccessPolicies[4], ErrMalformedPolicy, false}, // Test case - 6.
// contracting policy statement with recursive resources.
// should result in ErrPolicyNesting.
{bucketAccessPolicies[5], ErrPolicyNesting, false}, // Test case - 7.
// constructing policy statement with lexically close
// characters.
// should result in ErrNone.
{bucketAccessPolicies[6], ErrNone, true}, } for i, testCase := range testCases { apiErrCode := checkBucketPolicyResources("minio-bucket", &testCase.inputPolicy) if apiErrCode != ErrNone && testCase.shouldPass { t.Errorf("Test %d: Expected to pass, but failed with Errocode %v", i+1, apiErrCode) } if apiErrCode == ErrNone && !testCase.shouldPass { t.Errorf("Test %d: Expected to fail with ErrCode %v, but passed instead", i+1, testCase.apiErrCode) } // Failed as expected, but does it fail for the expected reason.
if apiErrCode != ErrNone && !testCase.shouldPass { if testCase.apiErrCode != apiErrCode { t.Errorf("Test %d: Expected to fail with error code %v, but instead failed with error code %v", i+1, testCase.apiErrCode, apiErrCode) } } } }
// Tests validate parsing of BucketAccessPolicy.
func TestParseBucketPolicy(t *testing.T) { // set Unsupported Actions.
setUnsupportedActions := func(statements []policyStatement) []policyStatement { // "s3:DeleteEverything"" is an Unsupported Action.
statements[0].Actions = set.CreateStringSet([]string{"s3:GetObject", "s3:ListBucket", "s3:PutObject", "s3:DeleteEverything"}...) return statements } // set unsupported Effect.
setUnsupportedEffect := func(statements []policyStatement) []policyStatement { // Effect "Don't allow" is Unsupported.
statements[0].Effect = "DontAllow" return statements } // set unsupported principals.
setUnsupportedPrincipals := func(statements []policyStatement) []policyStatement { // "User1111"" is an Unsupported Principal.
statements[0].Principal = map[string]interface{}{ "AWS": []string{"*", "User1111"}, } return statements } // set unsupported Resources.
setUnsupportedResources := func(statements []policyStatement) []policyStatement { // "s3:DeleteEverything"" is an Unsupported Action.
statements[0].Resources = set.CreateStringSet([]string{"my-resource"}...) return statements } // List of bucketPolicy used for test cases.
bucketAccesPolicies := []bucketPolicy{ // bucketPolicy - 0.
// bucketPolicy statement empty.
{Version: "1.0"}, // bucketPolicy - 1.
// bucketPolicy version empty.
{Version: "", Statements: []policyStatement{}}, // bucketPolicy - 2.
// Readonly bucketPolicy.
{Version: "1.0", Statements: getReadOnlyStatement("minio-bucket", "")}, // bucketPolicy - 3.
// Read-Write bucket policy.
{Version: "1.0", Statements: getReadWriteStatement("minio-bucket", "Asia/")}, // bucketPolicy - 4.
// Write only bucket policy.
{Version: "1.0", Statements: getWriteOnlyStatement("minio-bucket", "Asia/India/")}, // bucketPolicy - 5.
// bucketPolicy statement contains unsupported action.
{Version: "1.0", Statements: setUnsupportedActions(getReadOnlyStatement("minio-bucket", ""))}, // bucketPolicy - 6.
// bucketPolicy statement contains unsupported Effect.
{Version: "1.0", Statements: setUnsupportedEffect(getReadWriteStatement("minio-bucket", "Asia/"))}, // bucketPolicy - 7.
// bucketPolicy statement contains unsupported Principal.
{Version: "1.0", Statements: setUnsupportedPrincipals(getWriteOnlyStatement("minio-bucket", "Asia/India/"))}, // bucketPolicy - 8.
// bucketPolicy statement contains unsupported Resource.
{Version: "1.0", Statements: setUnsupportedResources(getWriteOnlyStatement("minio-bucket", "Asia/India/"))}, }
testCases := []struct { inputPolicy bucketPolicy // expected results.
expectedPolicy bucketPolicy err error // Flag indicating whether the test should pass.
shouldPass bool }{ // Test case - 1.
// bucketPolicy statement empty.
{bucketAccesPolicies[0], bucketPolicy{}, errors.New("Policy statement cannot be empty."), false}, // Test case - 2.
// bucketPolicy version empty.
{bucketAccesPolicies[1], bucketPolicy{}, errors.New("Policy version cannot be empty."), false}, // Test case - 3.
// Readonly bucketPolicy.
{bucketAccesPolicies[2], bucketAccesPolicies[2], nil, true}, // Test case - 4.
// Read-Write bucket policy.
{bucketAccesPolicies[3], bucketAccesPolicies[3], nil, true}, // Test case - 5.
// Write only bucket policy.
{bucketAccesPolicies[4], bucketAccesPolicies[4], nil, true}, // Test case - 6.
// bucketPolicy statement contains unsupported action.
{bucketAccesPolicies[5], bucketAccesPolicies[5], fmt.Errorf("Unsupported actions found: ‘set.StringSet{\"s3:DeleteEverything\":struct {}{}}’, please validate your policy document."), false}, // Test case - 7.
// bucketPolicy statement contains unsupported Effect.
{bucketAccesPolicies[6], bucketAccesPolicies[6], fmt.Errorf("Unsupported Effect found: ‘DontAllow’, please validate your policy document."), false}, // Test case - 8.
// bucketPolicy statement contains unsupported Principal.
{bucketAccesPolicies[7], bucketAccesPolicies[7], fmt.Errorf("Unsupported principals found: ‘set.StringSet{\"User1111\":struct {}{}}’, please validate your policy document."), false}, // Test case - 9.
// bucketPolicy statement contains unsupported Resource.
{bucketAccesPolicies[8], bucketAccesPolicies[8], fmt.Errorf("Unsupported resource style found: ‘my-resource’, please validate your policy document."), false}, } for i, testCase := range testCases { var buffer bytes.Buffer encoder := json.NewEncoder(&buffer) err := encoder.Encode(testCase.inputPolicy) if err != nil { t.Fatalf("Test %d: Couldn't Marshal bucket policy %s", i+1, err) }
var actualAccessPolicy = &bucketPolicy{} err = parseBucketPolicy(&buffer, actualAccessPolicy) if err != nil && testCase.shouldPass { t.Errorf("Test %d: Expected to pass, but failed with: <ERROR> %s", i+1, err.Error()) } if err == nil && !testCase.shouldPass { t.Errorf("Test %d: Expected to fail with <ERROR> \"%s\", but passed instead", i+1, testCase.err.Error()) } // Failed as expected, but does it fail for the expected reason.
if err != nil && !testCase.shouldPass { if err.Error() != testCase.err.Error() { t.Errorf("Test %d: Expected to fail with error \"%s\", but instead failed with error \"%s\"", i+1, testCase.err.Error(), err.Error()) } } // Test passes as expected, but the output values are verified for correctness here.
if err == nil && testCase.shouldPass { if testCase.expectedPolicy.String() != actualAccessPolicy.String() { t.Errorf("Test %d: The expected statements from resource statement generator doesn't match the actual statements", i+1) } } } }
|