diff --git a/auth/bucket_policy.go b/auth/bucket_policy.go index 9cd7991b..50996b60 100644 --- a/auth/bucket_policy.go +++ b/auth/bucket_policy.go @@ -29,19 +29,39 @@ func (p policyErr) Error() string { } const ( - policyErrResourceMismatch = policyErr("Action does not apply to any resource(s) in statement") - policyErrInvalidResource = policyErr("Policy has invalid resource") - policyErrInvalidPrincipal = policyErr("Invalid principal in policy") - policyErrInvalidAction = policyErr("Policy has invalid action") - policyErrInvalidPolicy = policyErr("This policy contains invalid Json") - policyErrInvalidFirstChar = policyErr("Policies must be valid JSON and the first byte must be '{'") - policyErrEmptyStatement = policyErr("Could not parse the policy: Statement is empty!") + policyErrResourceMismatch = policyErr("Action does not apply to any resource(s) in statement") + policyErrInvalidResource = policyErr("Policy has invalid resource") + policyErrInvalidPrincipal = policyErr("Invalid principal in policy") + policyErrInvalidAction = policyErr("Policy has invalid action") + policyErrInvalidPolicy = policyErr("This policy contains invalid Json") + policyErrInvalidFirstChar = policyErr("Policies must be valid JSON and the first byte must be '{'") + policyErrEmptyStatement = policyErr("Could not parse the policy: Statement is empty!") + policyErrMissingStatmentField = policyErr("Missing required field Statement") ) type BucketPolicy struct { Statement []BucketPolicyItem `json:"Statement"` } +func (bp *BucketPolicy) UnmarshalJSON(data []byte) error { + var tmp struct { + Statement *[]BucketPolicyItem `json:"Statement"` + } + + if err := json.Unmarshal(data, &tmp); err != nil { + return err + } + + // If Statement is nil (not present in JSON), return an error + if tmp.Statement == nil { + return policyErrMissingStatmentField + } + + // Assign the parsed value to the actual struct + bp.Statement = *tmp.Statement + return nil +} + func (bp *BucketPolicy) Validate(bucket string, iam IAMService) error { for _, statement := range bp.Statement { err := statement.Validate(bucket, iam) diff --git a/tests/integration/group-tests.go b/tests/integration/group-tests.go index b67d911a..ad7a147b 100644 --- a/tests/integration/group-tests.go +++ b/tests/integration/group-tests.go @@ -468,6 +468,7 @@ func TestGetBucketAcl(s *S3Conf) { func TestPutBucketPolicy(s *S3Conf) { PutBucketPolicy_non_existing_bucket(s) PutBucketPolicy_invalid_json(s) + PutBucketPolicy_statement_not_provided(s) PutBucketPolicy_empty_statement(s) PutBucketPolicy_invalid_effect(s) PutBucketPolicy_empty_actions_string(s) @@ -1059,6 +1060,7 @@ func GetIntTests() IntTests { "GetBucketAcl_success": GetBucketAcl_success, "PutBucketPolicy_non_existing_bucket": PutBucketPolicy_non_existing_bucket, "PutBucketPolicy_invalid_json": PutBucketPolicy_invalid_json, + "PutBucketPolicy_statement_not_provided": PutBucketPolicy_statement_not_provided, "PutBucketPolicy_empty_statement": PutBucketPolicy_empty_statement, "PutBucketPolicy_invalid_effect": PutBucketPolicy_invalid_effect, "PutBucketPolicy_empty_actions_string": PutBucketPolicy_empty_actions_string, diff --git a/tests/integration/tests.go b/tests/integration/tests.go index 9e3309ae..bfafc92f 100644 --- a/tests/integration/tests.go +++ b/tests/integration/tests.go @@ -11463,6 +11463,24 @@ func PutBucketPolicy_invalid_json(s *S3Conf) error { }) } +func PutBucketPolicy_statement_not_provided(s *S3Conf) error { + testName := "PutBucketPolicy_statement_not_provided" + return actionHandler(s, testName, func(s3client *s3.Client, bucket string) error { + doc := `{}` + + ctx, cancel := context.WithTimeout(context.Background(), shortTimeout) + _, err := s3client.PutBucketPolicy(ctx, &s3.PutBucketPolicyInput{ + Bucket: &bucket, + Policy: &doc, + }) + cancel() + if err := checkApiErr(err, getMalformedPolicyError("Missing required field Statement")); err != nil { + return err + } + return nil + }) +} + func PutBucketPolicy_empty_statement(s *S3Conf) error { testName := "PutBucketPolicy_empty_statement" return actionHandler(s, testName, func(s3client *s3.Client, bucket string) error {