From 45a1f7ae7cf0c5732a320604f574b6564eb09af3 Mon Sep 17 00:00:00 2001 From: niksis02 Date: Thu, 21 Aug 2025 15:24:42 +0400 Subject: [PATCH] feat: adds not implemented routes for bucket metrics configuration actions Closes #1445 Adds `NotImplemented` routes for bucket metrics configuration S3 actions: - `PutBucketMetricsConfiguration` - `GetBucketMetricsConfiguration` - `ListBucketMetricsConfigurations` - `DeleteBucketMetricsConfiguration` Adds the missing bucket actions to `supportedActionList` in bucket policy supported actions list. --- auth/bucket_policy_actions.go | 96 +++++++++++++++++++------------- metrics/actions.go | 4 ++ s3api/router.go | 56 +++++++++++++++++++ tests/integration/group-tests.go | 13 ++++- tests/integration/tests.go | 81 ++++++++++++++++++++------- 5 files changed, 189 insertions(+), 61 deletions(-) diff --git a/auth/bucket_policy_actions.go b/auth/bucket_policy_actions.go index 96cfb4a5..59b89357 100644 --- a/auth/bucket_policy_actions.go +++ b/auth/bucket_policy_actions.go @@ -74,50 +74,68 @@ const ( GetBucketLoggingAction Action = "s3:GetBucketLogging" PutBucketRequestPaymentAction Action = "s3:PutBucketRequestPayment" GetBucketRequestPaymentAction Action = "s3:GetBucketRequestPayment" + PutMetricsConfigurationAction Action = "s3:PutMetricsConfiguration" + GetMetricsConfigurationAction Action = "s3:GetMetricsConfiguration" AllActions Action = "s3:*" ) var supportedActionList = map[Action]struct{}{ - GetBucketAclAction: {}, - CreateBucketAction: {}, - PutBucketAclAction: {}, - DeleteBucketAction: {}, - PutBucketVersioningAction: {}, - GetBucketVersioningAction: {}, - PutBucketPolicyAction: {}, - GetBucketPolicyAction: {}, - DeleteBucketPolicyAction: {}, - AbortMultipartUploadAction: {}, - ListMultipartUploadPartsAction: {}, - ListBucketMultipartUploadsAction: {}, - PutObjectAction: {}, - GetObjectAction: {}, - GetObjectVersionAction: {}, - DeleteObjectAction: {}, - GetObjectAclAction: {}, - GetObjectAttributesAction: {}, - PutObjectAclAction: {}, - RestoreObjectAction: {}, - GetBucketTaggingAction: {}, - PutBucketTaggingAction: {}, - GetObjectTaggingAction: {}, - PutObjectTaggingAction: {}, - DeleteObjectTaggingAction: {}, - ListBucketVersionsAction: {}, - ListBucketAction: {}, - GetBucketObjectLockConfigurationAction: {}, - PutBucketObjectLockConfigurationAction: {}, - GetObjectLegalHoldAction: {}, - PutObjectLegalHoldAction: {}, - GetObjectRetentionAction: {}, - PutObjectRetentionAction: {}, - BypassGovernanceRetentionAction: {}, - PutBucketOwnershipControlsAction: {}, - GetBucketOwnershipControlsAction: {}, - PutBucketCorsAction: {}, - GetBucketCorsAction: {}, - AllActions: {}, + GetBucketAclAction: {}, + CreateBucketAction: {}, + PutBucketAclAction: {}, + DeleteBucketAction: {}, + PutBucketVersioningAction: {}, + GetBucketVersioningAction: {}, + PutBucketPolicyAction: {}, + GetBucketPolicyAction: {}, + DeleteBucketPolicyAction: {}, + AbortMultipartUploadAction: {}, + ListMultipartUploadPartsAction: {}, + ListBucketMultipartUploadsAction: {}, + PutObjectAction: {}, + GetObjectAction: {}, + GetObjectVersionAction: {}, + DeleteObjectAction: {}, + GetObjectAclAction: {}, + GetObjectAttributesAction: {}, + PutObjectAclAction: {}, + RestoreObjectAction: {}, + GetBucketTaggingAction: {}, + PutBucketTaggingAction: {}, + GetObjectTaggingAction: {}, + PutObjectTaggingAction: {}, + DeleteObjectTaggingAction: {}, + ListBucketVersionsAction: {}, + ListBucketAction: {}, + GetBucketObjectLockConfigurationAction: {}, + PutBucketObjectLockConfigurationAction: {}, + GetObjectLegalHoldAction: {}, + PutObjectLegalHoldAction: {}, + GetObjectRetentionAction: {}, + PutObjectRetentionAction: {}, + BypassGovernanceRetentionAction: {}, + PutBucketOwnershipControlsAction: {}, + GetBucketOwnershipControlsAction: {}, + PutBucketCorsAction: {}, + GetBucketCorsAction: {}, + PutAnalyticsConfigurationAction: {}, + GetAnalyticsConfigurationAction: {}, + PutEncryptionConfigurationAction: {}, + GetEncryptionConfigurationAction: {}, + PutIntelligentTieringConfigurationAction: {}, + GetIntelligentTieringConfigurationAction: {}, + PutInventoryConfigurationAction: {}, + GetInventoryConfigurationAction: {}, + PutLifecycleConfigurationAction: {}, + GetLifecycleConfigurationAction: {}, + PutBucketLoggingAction: {}, + GetBucketLoggingAction: {}, + PutBucketRequestPaymentAction: {}, + GetBucketRequestPaymentAction: {}, + PutMetricsConfigurationAction: {}, + GetMetricsConfigurationAction: {}, + AllActions: {}, } var supportedObjectActionList = map[Action]struct{}{ diff --git a/metrics/actions.go b/metrics/actions.go index 615182fc..2fe63627 100644 --- a/metrics/actions.go +++ b/metrics/actions.go @@ -98,6 +98,10 @@ var ( ActionGetBucketLogging = "s3_GetBucketLogging" ActionPutBucketRequestPayment = "s3_PutBucketRequestPayment" ActionGetBucketRequestPayment = "s3_GetBucketRequestPayment" + ActionPutBucketMetricsConfiguration = "s3_PutBucketMetricsConfiguration" + ActionGetBucketMetricsConfiguration = "s3_GetBucketMetricsConfiguration" + ActionListBucketMetricsConfigurations = "s3_ListBucketMetricsConfigurations" + ActionDeleteBucketMetricsConfiguration = "s3_DeleteBucketMetricsConfiguration" // Admin actions ActionAdminCreateUser = "admin_CreateUser" diff --git a/s3api/router.go b/s3api/router.go index cbcdefea..e02cbc3b 100644 --- a/s3api/router.go +++ b/s3api/router.go @@ -300,6 +300,20 @@ func (sa *S3ApiRouter) Init(app *fiber.App, be backend.Backend, iam auth.IAMServ middlewares.ParseAcl(be), ), ) + bucketRouter.Put("", + middlewares.MatchQueryArgs("metrics"), + controllers.ProcessHandlers( + ctrl.HandleErrorRoute(s3err.GetAPIError(s3err.ErrNotImplemented)), + metrics.ActionPutBucketMetricsConfiguration, + services, + middlewares.BucketObjectNameValidator(), + middlewares.AuthorizePublicBucketAccess(be, metrics.ActionPutBucketMetricsConfiguration, auth.PutMetricsConfigurationAction, 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, @@ -456,6 +470,20 @@ func (sa *S3ApiRouter) Init(app *fiber.App, be backend.Backend, iam auth.IAMServ middlewares.ParseAcl(be), ), ) + bucketRouter.Delete("", + middlewares.MatchQueryArgs("metrics"), + controllers.ProcessHandlers( + ctrl.HandleErrorRoute(s3err.GetAPIError(s3err.ErrNotImplemented)), + metrics.ActionDeleteBucketMetricsConfiguration, + services, + middlewares.BucketObjectNameValidator(), + middlewares.AuthorizePublicBucketAccess(be, metrics.ActionDeleteBucketMetricsConfiguration, auth.PutMetricsConfigurationAction, 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, @@ -737,6 +765,34 @@ func (sa *S3ApiRouter) Init(app *fiber.App, be backend.Backend, iam auth.IAMServ middlewares.ParseAcl(be), ), ) + bucketRouter.Get("", + middlewares.MatchQueryArgs("metrics", "id"), + controllers.ProcessHandlers( + ctrl.HandleErrorRoute(s3err.GetAPIError(s3err.ErrNotImplemented)), + metrics.ActionGetBucketMetricsConfiguration, + services, + middlewares.BucketObjectNameValidator(), + middlewares.AuthorizePublicBucketAccess(be, metrics.ActionGetBucketMetricsConfiguration, auth.GetMetricsConfigurationAction, auth.PermissionRead), + middlewares.VerifyPresignedV4Signature(root, iam, region, debug), + middlewares.VerifyV4Signature(root, iam, region, debug), + middlewares.VerifyMD5Body(), + middlewares.ParseAcl(be), + ), + ) + bucketRouter.Get("", + middlewares.MatchQueryArgs("metrics"), + controllers.ProcessHandlers( + ctrl.HandleErrorRoute(s3err.GetAPIError(s3err.ErrNotImplemented)), + metrics.ActionListBucketMetricsConfigurations, + services, + middlewares.BucketObjectNameValidator(), + middlewares.AuthorizePublicBucketAccess(be, metrics.ActionListBucketMetricsConfigurations, auth.GetMetricsConfigurationAction, 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 a588233d..816187a1 100644 --- a/tests/integration/group-tests.go +++ b/tests/integration/group-tests.go @@ -493,7 +493,6 @@ func TestPutBucketPolicy(s *S3Conf) { PutBucketPolicy_empty_actions_string(s) PutBucketPolicy_empty_actions_array(s) PutBucketPolicy_invalid_action(s) - PutBucketPolicy_unsupported_action(s) PutBucketPolicy_incorrect_action_wildcard_usage(s) PutBucketPolicy_empty_principals_string(s) PutBucketPolicy_empty_principals_array(s) @@ -648,9 +647,14 @@ func TestNotImplementedActions(s *S3Conf) { // bucket logging actions PutBucketLogging_not_implemented(s) GetBucketLogging_not_implemented(s) - // request payment actions + // bucket request payment actions PutBucketRequestPayment_not_implemented(s) GetBucketRequestPayment_not_implemented(s) + // bucket metrics configuration actions + PutBucketMetricsConfiguration_not_implemented(s) + GetBucketMetricsConfiguration_not_implemented(s) + ListBucketMetricsConfigurations_not_implemented(s) + DeleteBucketMetricsConfiguration_not_implemented(s) } func TestWORMProtection(s *S3Conf) { @@ -1298,7 +1302,6 @@ func GetIntTests() IntTests { "PutBucketPolicy_empty_actions_string": PutBucketPolicy_empty_actions_string, "PutBucketPolicy_empty_actions_array": PutBucketPolicy_empty_actions_array, "PutBucketPolicy_invalid_action": PutBucketPolicy_invalid_action, - "PutBucketPolicy_unsupported_action": PutBucketPolicy_unsupported_action, "PutBucketPolicy_incorrect_action_wildcard_usage": PutBucketPolicy_incorrect_action_wildcard_usage, "PutBucketPolicy_empty_principals_string": PutBucketPolicy_empty_principals_string, "PutBucketPolicy_empty_principals_array": PutBucketPolicy_empty_principals_array, @@ -1407,6 +1410,10 @@ func GetIntTests() IntTests { "GetBucketLogging_not_implemented": GetBucketLogging_not_implemented, "PutBucketRequestPayment_not_implemented": PutBucketRequestPayment_not_implemented, "GetBucketRequestPayment_not_implemented": GetBucketRequestPayment_not_implemented, + "PutBucketMetricsConfiguration_not_implemented": PutBucketMetricsConfiguration_not_implemented, + "GetBucketMetricsConfiguration_not_implemented": GetBucketMetricsConfiguration_not_implemented, + "ListBucketMetricsConfigurations_not_implemented": ListBucketMetricsConfigurations_not_implemented, + "DeleteBucketMetricsConfiguration_not_implemented": DeleteBucketMetricsConfiguration_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 aa99af5c..643a3ce4 100644 --- a/tests/integration/tests.go +++ b/tests/integration/tests.go @@ -12884,25 +12884,6 @@ func PutBucketPolicy_invalid_action(s *S3Conf) error { }) } -func PutBucketPolicy_unsupported_action(s *S3Conf) error { - testName := "PutBucketPolicy_unsupported_action" - return actionHandler(s, testName, func(s3client *s3.Client, bucket string) error { - doc := genPolicyDoc("Allow", `"*"`, `"s3:PutLifecycleConfiguration"`, `"arn:aws:s3:::*"`) - - ctx, cancel := context.WithTimeout(context.Background(), shortTimeout) - _, err := s3client.PutBucketPolicy(ctx, &s3.PutBucketPolicyInput{ - Bucket: &bucket, - Policy: &doc, - }) - cancel() - - if err := checkApiErr(err, getMalformedPolicyError("Policy has invalid action")); err != nil { - return err - } - return nil - }) -} - func PutBucketPolicy_incorrect_action_wildcard_usage(s *S3Conf) error { testName := "PutBucketPolicy_incorrect_action_wildcard_usage" return actionHandler(s, testName, func(s3client *s3.Client, bucket string) error { @@ -15789,6 +15770,68 @@ func GetBucketRequestPayment_not_implemented(s *S3Conf) error { }) } +func PutBucketMetricsConfiguration_not_implemented(s *S3Conf) error { + testName := "PutBucketMetricsConfiguration_not_implemented" + return actionHandler(s, testName, func(s3client *s3.Client, bucket string) error { + ctx, cancel := context.WithTimeout(context.Background(), shortTimeout) + _, err := s3client.PutBucketMetricsConfiguration(ctx, + &s3.PutBucketMetricsConfigurationInput{ + Bucket: &bucket, + Id: getPtr("unique_id"), + MetricsConfiguration: &types.MetricsConfiguration{ + Id: getPtr("EntireBucket"), + }, + }) + cancel() + + return checkApiErr(err, s3err.GetAPIError(s3err.ErrNotImplemented)) + }) +} + +func GetBucketMetricsConfiguration_not_implemented(s *S3Conf) error { + testName := "GetBucketMetricsConfiguration_not_implemented" + return actionHandler(s, testName, func(s3client *s3.Client, bucket string) error { + ctx, cancel := context.WithTimeout(context.Background(), shortTimeout) + _, err := s3client.GetBucketMetricsConfiguration(ctx, + &s3.GetBucketMetricsConfigurationInput{ + Bucket: &bucket, + Id: getPtr("unique_id"), + }) + cancel() + + return checkApiErr(err, s3err.GetAPIError(s3err.ErrNotImplemented)) + }) +} + +func ListBucketMetricsConfigurations_not_implemented(s *S3Conf) error { + testName := "ListBucketMetricsConfigurations_not_implemented" + return actionHandler(s, testName, func(s3client *s3.Client, bucket string) error { + ctx, cancel := context.WithTimeout(context.Background(), shortTimeout) + _, err := s3client.ListBucketMetricsConfigurations(ctx, + &s3.ListBucketMetricsConfigurationsInput{ + Bucket: &bucket, + }) + cancel() + + return checkApiErr(err, s3err.GetAPIError(s3err.ErrNotImplemented)) + }) +} + +func DeleteBucketMetricsConfiguration_not_implemented(s *S3Conf) error { + testName := "DeleteBucketMetricsConfiguration_not_implemented" + return actionHandler(s, testName, func(s3client *s3.Client, bucket string) error { + ctx, cancel := context.WithTimeout(context.Background(), shortTimeout) + _, err := s3client.DeleteBucketMetricsConfiguration(ctx, + &s3.DeleteBucketMetricsConfigurationInput{ + Bucket: &bucket, + Id: getPtr("unique_id"), + }) + 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 {