diff --git a/auth/bucket_policy_actions.go b/auth/bucket_policy_actions.go index 8057187..43ffea3 100644 --- a/auth/bucket_policy_actions.go +++ b/auth/bucket_policy_actions.go @@ -84,6 +84,8 @@ const ( GetBucketNotificationAction Action = "s3:GetBucketNotification" PutAccelerateConfigurationAction Action = "s3:PutAccelerateConfiguration" GetAccelerateConfigurationAction Action = "s3:GetAccelerateConfiguration" + PutBucketWebsiteAction Action = "s3:PutBucketWebsite" + GetBucketWebsiteAction Action = "s3:GetBucketWebsite" AllActions Action = "s3:*" ) @@ -151,6 +153,8 @@ var supportedActionList = map[Action]struct{}{ GetBucketNotificationAction: {}, PutAccelerateConfigurationAction: {}, GetAccelerateConfigurationAction: {}, + PutBucketWebsiteAction: {}, + GetBucketWebsiteAction: {}, AllActions: {}, } diff --git a/metrics/actions.go b/metrics/actions.go index f79ca1f..d0eeb9f 100644 --- a/metrics/actions.go +++ b/metrics/actions.go @@ -112,6 +112,9 @@ var ( ActionGetBucketNotificationConfiguration = "s3_GetBucketNotificationConfiguration" ActionPutBucketAccelerateConfiguration = "s3_PutBucketAccelerateConfiguration" ActionGetBucketAccelerateConfiguration = "s3_GetBucketAccelerateConfiguration" + ActionPutBucketWebsite = "s3_PutBucketWebsite" + ActionGetBucketWebsite = "s3_GetBucketWebsite" + ActionDeleteBucketWebsite = "s3_DeleteBucketWebsite" // Admin actions ActionAdminCreateUser = "admin_CreateUser" @@ -478,4 +481,16 @@ func init() { Name: "GetBucketAccelerateConfiguration", Service: "s3", } + ActionMap[ActionPutBucketWebsite] = Action{ + Name: "PutBucketWebsite", + Service: "s3", + } + ActionMap[ActionGetBucketWebsite] = Action{ + Name: "GetBucketWebsite", + Service: "s3", + } + ActionMap[ActionDeleteBucketWebsite] = Action{ + Name: "DeleteBucketWebsite", + Service: "s3", + } } diff --git a/s3api/router.go b/s3api/router.go index b791600..6eafbc1 100644 --- a/s3api/router.go +++ b/s3api/router.go @@ -370,6 +370,20 @@ func (sa *S3ApiRouter) Init(app *fiber.App, be backend.Backend, iam auth.IAMServ middlewares.ParseAcl(be), ), ) + bucketRouter.Put("", + middlewares.MatchQueryArgs("website"), + controllers.ProcessHandlers( + ctrl.HandleErrorRoute(s3err.GetAPIError(s3err.ErrNotImplemented)), + metrics.ActionPutBucketWebsite, + services, + middlewares.BucketObjectNameValidator(), + middlewares.AuthorizePublicBucketAccess(be, metrics.ActionPutBucketWebsite, auth.PutBucketWebsiteAction, auth.PermissionWrite), + middlewares.VerifyPresignedV4Signature(root, iam, region, debug), + middlewares.VerifyV4Signature(root, iam, region, debug), + middlewares.VerifyMD5Body(), + middlewares.ParseAcl(be), + ), + ) bucketRouter.Put("", controllers.ProcessHandlers( ctrl.CreateBucket, @@ -568,6 +582,20 @@ func (sa *S3ApiRouter) Init(app *fiber.App, be backend.Backend, iam auth.IAMServ middlewares.ParseAcl(be), ), ) + bucketRouter.Delete("", + middlewares.MatchQueryArgs("website"), + controllers.ProcessHandlers( + ctrl.HandleErrorRoute(s3err.GetAPIError(s3err.ErrNotImplemented)), + metrics.ActionDeleteBucketWebsite, + services, + middlewares.BucketObjectNameValidator(), + middlewares.AuthorizePublicBucketAccess(be, metrics.ActionDeleteBucketWebsite, auth.PutBucketWebsiteAction, auth.PermissionWrite), + middlewares.VerifyPresignedV4Signature(root, iam, region, debug), + middlewares.VerifyV4Signature(root, iam, region, debug), + middlewares.VerifyMD5Body(), + middlewares.ParseAcl(be), + ), + ) bucketRouter.Delete("", controllers.ProcessHandlers( ctrl.DeleteBucket, @@ -933,6 +961,20 @@ func (sa *S3ApiRouter) Init(app *fiber.App, be backend.Backend, iam auth.IAMServ middlewares.ParseAcl(be), ), ) + bucketRouter.Get("", + middlewares.MatchQueryArgs("website"), + controllers.ProcessHandlers( + ctrl.HandleErrorRoute(s3err.GetAPIError(s3err.ErrNotImplemented)), + metrics.ActionGetBucketWebsite, + services, + middlewares.BucketObjectNameValidator(), + middlewares.AuthorizePublicBucketAccess(be, metrics.ActionGetBucketWebsite, auth.GetBucketWebsiteAction, auth.PermissionRead), + middlewares.VerifyPresignedV4Signature(root, iam, region, debug), + middlewares.VerifyV4Signature(root, iam, region, debug), + middlewares.VerifyMD5Body(), + middlewares.ParseAcl(be), + ), + ) bucketRouter.Get("", middlewares.MatchQueryArgWithValue("list-type", "2"), controllers.ProcessHandlers( diff --git a/tests/integration/group-tests.go b/tests/integration/group-tests.go index 636814a..05eab24 100644 --- a/tests/integration/group-tests.go +++ b/tests/integration/group-tests.go @@ -669,6 +669,10 @@ func TestNotImplementedActions(s *S3Conf) { // bucket acceleration actions PutBucketAccelerateConfiguration_not_implemented(s) GetBucketAccelerateConfiguration_not_implemented(s) + // bucket website actions + PutBucketWebsite_not_implemented(s) + GetBucketWebsite_not_implemented(s) + DeleteBucketWebsite_not_implemented(s) } func TestWORMProtection(s *S3Conf) { @@ -1438,6 +1442,9 @@ func GetIntTests() IntTests { "GetBucketNotificationConfiguratio_not_implemented": GetBucketNotificationConfiguratio_not_implemented, "PutBucketAccelerateConfiguration_not_implemented": PutBucketAccelerateConfiguration_not_implemented, "GetBucketAccelerateConfiguration_not_implemented": GetBucketAccelerateConfiguration_not_implemented, + "PutBucketWebsite_not_implemented": PutBucketWebsite_not_implemented, + "GetBucketWebsite_not_implemented": GetBucketWebsite_not_implemented, + "DeleteBucketWebsite_not_implemented": DeleteBucketWebsite_not_implemented, "WORMProtection_bucket_object_lock_configuration_compliance_mode": WORMProtection_bucket_object_lock_configuration_compliance_mode, "WORMProtection_bucket_object_lock_configuration_governance_mode": WORMProtection_bucket_object_lock_configuration_governance_mode, "WORMProtection_bucket_object_lock_governance_bypass_delete": WORMProtection_bucket_object_lock_governance_bypass_delete, diff --git a/tests/integration/tests.go b/tests/integration/tests.go index ddceca5..9ee9122 100644 --- a/tests/integration/tests.go +++ b/tests/integration/tests.go @@ -15996,6 +15996,53 @@ func GetBucketAccelerateConfiguration_not_implemented(s *S3Conf) error { }) } +func PutBucketWebsite_not_implemented(s *S3Conf) error { + testName := "PutBucketWebsite_not_implemented" + return actionHandler(s, testName, func(s3client *s3.Client, bucket string) error { + ctx, cancel := context.WithTimeout(context.Background(), shortTimeout) + _, err := s3client.PutBucketWebsite(ctx, + &s3.PutBucketWebsiteInput{ + Bucket: &bucket, + WebsiteConfiguration: &types.WebsiteConfiguration{ + IndexDocument: &types.IndexDocument{ + Suffix: getPtr("suffix"), + }, + }, + }) + cancel() + + return checkApiErr(err, s3err.GetAPIError(s3err.ErrNotImplemented)) + }) +} + +func GetBucketWebsite_not_implemented(s *S3Conf) error { + testName := "GetBucketWebsite_not_implemented" + return actionHandler(s, testName, func(s3client *s3.Client, bucket string) error { + ctx, cancel := context.WithTimeout(context.Background(), shortTimeout) + _, err := s3client.GetBucketWebsite(ctx, + &s3.GetBucketWebsiteInput{ + Bucket: &bucket, + }) + cancel() + + return checkApiErr(err, s3err.GetAPIError(s3err.ErrNotImplemented)) + }) +} + +func DeleteBucketWebsite_not_implemented(s *S3Conf) error { + testName := "DeleteBucketWebsite_not_implemented" + return actionHandler(s, testName, func(s3client *s3.Client, bucket string) error { + ctx, cancel := context.WithTimeout(context.Background(), shortTimeout) + _, err := s3client.DeleteBucketWebsite(ctx, + &s3.DeleteBucketWebsiteInput{ + Bucket: &bucket, + }) + cancel() + + return checkApiErr(err, s3err.GetAPIError(s3err.ErrNotImplemented)) + }) +} + func WORMProtection_bucket_object_lock_configuration_compliance_mode(s *S3Conf) error { testName := "WORMProtection_bucket_object_lock_configuration_compliance_mode" return actionHandler(s, testName, func(s3client *s3.Client, bucket string) error {