diff --git a/cmd/versitygw/test.go b/cmd/versitygw/test.go index 822612c..c1c5217 100644 --- a/cmd/versitygw/test.go +++ b/cmd/versitygw/test.go @@ -268,11 +268,9 @@ func getAction(tf testFunc) func(*cli.Context) error { func extractIntTests() (commands []*cli.Command) { tests := integration.GetIntTests() for key, val := range tests { - testKey := key - testFunc := val commands = append(commands, &cli.Command{ - Name: testKey, - Usage: fmt.Sprintf("Runs %v integration test", testKey), + Name: key, + Usage: fmt.Sprintf("Runs %v integration test", key), Action: func(ctx *cli.Context) error { opts := []integration.Option{ integration.WithAccess(awsID), @@ -285,7 +283,7 @@ func extractIntTests() (commands []*cli.Command) { } s := integration.NewS3Conf(opts...) - err := testFunc(s) + err := val(s) return err }, }) diff --git a/integration/group-tests.go b/integration/group-tests.go index ab6899e..24d8488 100644 --- a/integration/group-tests.go +++ b/integration/group-tests.go @@ -26,6 +26,8 @@ func TestCreateBucket(s *S3Conf) { CreateBucket_invalid_bucket_name(s) CreateBucket_existing_bucket(s) CreateBucket_as_user(s) + CreateBucket_default_acl(s) + CreateBucket_non_default_acl(s) CreateDeleteBucket_success(s) } @@ -251,6 +253,8 @@ func GetIntTests() IntTests { "CreateBucket_existing_bucket": CreateBucket_existing_bucket, "CreateBucket_as_user": CreateBucket_as_user, "CreateDeleteBucket_success": CreateDeleteBucket_success, + "CreateBucket_default_acl": CreateBucket_default_acl, + "CreateBucket_non_default_acl": CreateBucket_non_default_acl, "HeadBucket_non_existing_bucket": HeadBucket_non_existing_bucket, "HeadBucket_success": HeadBucket_success, "ListBuckets_as_user": ListBuckets_as_user, @@ -263,7 +267,6 @@ func GetIntTests() IntTests { "PutObject_special_chars": PutObject_special_chars, "PutObject_invalid_long_tags": PutObject_invalid_long_tags, "PutObject_success": PutObject_success, - "PutObject_invalid_credentials": PutObject_invalid_credentials, "HeadObject_non_existing_object": HeadObject_non_existing_object, "HeadObject_success": HeadObject_success, "GetObject_non_existing_key": GetObject_non_existing_key, diff --git a/integration/tests.go b/integration/tests.go index 9aa5402..c014a45 100644 --- a/integration/tests.go +++ b/integration/tests.go @@ -706,6 +706,116 @@ func CreateBucket_existing_bucket(s *S3Conf) error { return nil } +func CreateBucket_default_acl(s *S3Conf) error { + testName := "CreateBucket_default_acl" + runF(testName) + + bucket := getBucketName() + client := s3.NewFromConfig(s.Config()) + + err := setup(s, bucket) + if err != nil { + failF("%v: %v", testName, err) + return fmt.Errorf("%v: %w", testName, err) + } + + ctx, cancel := context.WithTimeout(context.Background(), shortTimeout) + out, err := client.GetBucketAcl(ctx, &s3.GetBucketAclInput{Bucket: &bucket}) + cancel() + if err != nil { + failF("%v: %v", testName, err) + return fmt.Errorf("%v: %w", testName, err) + } + + if *out.Owner.ID != s.awsID { + failF("%v: expected bucket owner to be %v, instead got %v", testName, s.awsID, *out.Owner.ID) + return fmt.Errorf("%v: expected bucket owner to be %v, instead got %v", testName, s.awsID, *out.Owner.ID) + } + + if len(out.Grants) != 0 { + failF("%v: expected grants to be empty instead got %v", testName, len(out.Grants)) + return fmt.Errorf("%v: expected grants to be empty instead got %v", testName, len(out.Grants)) + } + + err = teardown(s, bucket) + if err != nil { + failF("%v: %v", err) + return fmt.Errorf("%v: %w", testName, err) + } + + passF(testName) + return nil +} + +func CreateBucket_non_default_acl(s *S3Conf) error { + testName := "CreateBucket_non_default_acl" + runF(testName) + + err := createUsers(s, []user{ + {"grt1", "grt1secret", "user"}, + {"grt2", "grt2secret", "user"}, + {"grt3", "grt3secret", "user"}, + }) + if err != nil { + failF("%v: %v", err) + return fmt.Errorf("%v: %w", testName, err) + } + + grants := []types.Grant{ + { + Grantee: &types.Grantee{ + ID: getPtr("grt1"), + }, + Permission: types.PermissionFullControl, + }, + { + Grantee: &types.Grantee{ + ID: getPtr("grt2"), + }, + Permission: types.PermissionReadAcp, + }, + { + Grantee: &types.Grantee{ + ID: getPtr("grt3"), + }, + Permission: types.PermissionWrite, + }, + } + + bucket := getBucketName() + client := s3.NewFromConfig(s.Config()) + + ctx, cancel := context.WithTimeout(context.Background(), shortTimeout) + _, err = client.CreateBucket(ctx, &s3.CreateBucketInput{Bucket: &bucket, GrantFullControl: getPtr("grt1"), GrantReadACP: getPtr("grt2"), GrantWrite: getPtr("grt3")}) + cancel() + if err != nil { + failF("%v: %v", err) + return fmt.Errorf("%v: %w", testName, err) + } + + ctx, cancel = context.WithTimeout(context.Background(), shortTimeout) + out, err := client.GetBucketAcl(ctx, &s3.GetBucketAclInput{Bucket: &bucket}) + cancel() + if err != nil { + failF("%v: %v", testName, err) + return fmt.Errorf("%v: %w", testName, err) + } + + if !compareGrants(out.Grants, grants) { + failF("%v: expected bucket acl grants to be %v, instead got %v", testName, grants, out.Grants) + return fmt.Errorf("%v: expected bucket acl grants to be %v, instead got %v", testName, grants, out.Grants) + } + + err = teardown(s, bucket) + if err != nil { + failF("%v: %v", err) + return fmt.Errorf("%v: %w", testName, err) + } + + passF(testName) + return nil +} + func HeadBucket_non_existing_bucket(s *S3Conf) error { testName := "HeadBucket_non_existing_bucket" return actionHandler(s, testName, func(s3client *s3.Client, bucket string) error { diff --git a/s3api/controllers/base.go b/s3api/controllers/base.go index 8b3a47a..6f64d77 100644 --- a/s3api/controllers/base.go +++ b/s3api/controllers/base.go @@ -16,7 +16,6 @@ package controllers import ( "bytes" - "encoding/json" "encoding/xml" "errors" "fmt" @@ -408,16 +407,29 @@ func (c S3ApiController) PutBucketActions(ctx *fiber.Ctx) error { return SendResponse(ctx, s3err.GetAPIError(s3err.ErrInvalidBucketName), &MetaOpts{Logger: c.logger, Action: "CreateBucket"}) } + if acl != "" && grants != "" { + return SendResponse(ctx, s3err.GetAPIError(s3err.ErrInvalidRequest), &MetaOpts{Logger: c.logger, Action: "PutBucketAcl", BucketOwner: acct.Access}) + } + defACL := auth.ACL{ACL: "private", Owner: acct.Access, Grantees: []auth.Grantee{}} - jsonACL, err := json.Marshal(defACL) + + updAcl, err := auth.UpdateACL(&s3.PutBucketAclInput{ + GrantFullControl: &grantFullControl, + GrantRead: &grantRead, + GrantReadACP: &grantReadACP, + GrantWrite: &granWrite, + GrantWriteACP: &grantWriteACP, + AccessControlPolicy: &types.AccessControlPolicy{Owner: &types.Owner{ID: &acct.Access}}, + ACL: types.BucketCannedACL(acl), + }, defACL, c.iam) if err != nil { - return SendResponse(ctx, fmt.Errorf("marshal acl: %w", err), &MetaOpts{Logger: c.logger, Action: "CreateBucket", BucketOwner: acct.Access}) + return SendResponse(ctx, err, &MetaOpts{Logger: c.logger, Action: "CreateBucket", BucketOwner: acct.Access}) } err = c.be.CreateBucket(ctx.Context(), &s3.CreateBucketInput{ Bucket: &bucket, ObjectOwnership: types.ObjectOwnership(acct.Access), - }, jsonACL) + }, updAcl) return SendResponse(ctx, err, &MetaOpts{Logger: c.logger, Action: "CreateBucket", BucketOwner: acct.Access}) }