From 64e705f49a0945a2ac05fedfa24f2198da151d58 Mon Sep 17 00:00:00 2001 From: niksis02 Date: Tue, 1 Jul 2025 23:51:49 +0400 Subject: [PATCH] feat: adds the bucket/object name validator middleware --- .../bucket_object_name_validator.go | 36 +++++++++++++++++++ s3api/server.go | 2 ++ s3err/s3err.go | 6 ++++ tests/integration/tests.go | 8 ++--- 4 files changed, 48 insertions(+), 4 deletions(-) create mode 100644 s3api/middlewares/bucket_object_name_validator.go diff --git a/s3api/middlewares/bucket_object_name_validator.go b/s3api/middlewares/bucket_object_name_validator.go new file mode 100644 index 00000000..f5d2db26 --- /dev/null +++ b/s3api/middlewares/bucket_object_name_validator.go @@ -0,0 +1,36 @@ +// Copyright 2023 Versity Software +// This file is 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 middlewares + +import ( + "github.com/gofiber/fiber/v2" + "github.com/versity/versitygw/metrics" + "github.com/versity/versitygw/s3api/utils" + "github.com/versity/versitygw/s3err" + "github.com/versity/versitygw/s3log" +) + +func ValidateBucketObjectNames(l s3log.AuditLogger, mm *metrics.Manager) fiber.Handler { + return func(ctx *fiber.Ctx) error { + bucket, object := parsePath(ctx.Path()) + if bucket != "" && !utils.IsValidBucketName(bucket) { + return sendResponse(ctx, s3err.GetAPIError(s3err.ErrInvalidBucketName), l, mm) + } + if object != "" && !utils.IsObjectNameValid(object) { + return sendResponse(ctx, s3err.GetAPIError(s3err.ErrBadRequest), l, mm) + } + return ctx.Next() + } +} diff --git a/s3api/server.go b/s3api/server.go index c23b0650..9b65f604 100644 --- a/s3api/server.go +++ b/s3api/server.go @@ -91,6 +91,8 @@ func New( app.Use(middlewares.DebugLogger()) } + app.Use(middlewares.ValidateBucketObjectNames(l, mm)) + // Public buckets access checker app.Use(middlewares.AuthorizePublicBucketAccess(be, l, mm)) diff --git a/s3err/s3err.go b/s3err/s3err.go index 0d8b41fc..59aca425 100644 --- a/s3err/s3err.go +++ b/s3err/s3err.go @@ -167,6 +167,7 @@ const ( ErrChecksumTypeWithAlgo ErrInvalidChecksumHeader ErrTrailerHeaderNotSupported + ErrBadRequest // Non-AWS errors ErrExistingObjectIsDirectory @@ -726,6 +727,11 @@ var errorCodeResponse = map[ErrorCode]APIError{ Description: "The value specified in the x-amz-trailer header is not supported", HTTPStatusCode: http.StatusBadRequest, }, + ErrBadRequest: { + Code: "400", + Description: "Bad Request", + HTTPStatusCode: http.StatusBadRequest, + }, // non aws errors ErrExistingObjectIsDirectory: { diff --git a/tests/integration/tests.go b/tests/integration/tests.go index a2351211..d45906c0 100644 --- a/tests/integration/tests.go +++ b/tests/integration/tests.go @@ -9995,7 +9995,7 @@ func AbortMultipartUpload_non_existing_bucket(s *S3Conf) error { return actionHandler(s, testName, func(s3client *s3.Client, bucket string) error { ctx, cancel := context.WithTimeout(context.Background(), shortTimeout) _, err := s3client.AbortMultipartUpload(ctx, &s3.AbortMultipartUploadInput{ - Bucket: getPtr("incorrectBucket"), + Bucket: getPtr("incorrectbucket"), Key: getPtr("my-obj"), UploadId: getPtr("uploadId"), }) @@ -12328,7 +12328,7 @@ func PutBucketPolicy_non_existing_bucket(s *S3Conf) error { ctx, cancel := context.WithTimeout(context.Background(), shortTimeout) doc := genPolicyDoc("Allow", `"*"`, `"s3:*"`, fmt.Sprintf(`"arn:aws:s3:::%v"`, bucket)) _, err := s3client.PutBucketPolicy(ctx, &s3.PutBucketPolicyInput{ - Bucket: getPtr("non_existing_bucket"), + Bucket: getPtr("nonexistingbucket"), Policy: &doc, }) cancel() @@ -13003,7 +13003,7 @@ func GetBucketPolicy_non_existing_bucket(s *S3Conf) error { return actionHandler(s, testName, func(s3client *s3.Client, bucket string) error { ctx, cancel := context.WithTimeout(context.Background(), shortTimeout) _, err := s3client.GetBucketPolicy(ctx, &s3.GetBucketPolicyInput{ - Bucket: getPtr("non_existing_bucket"), + Bucket: getPtr("nonexistingbucket"), }) cancel() @@ -13069,7 +13069,7 @@ func DeleteBucketPolicy_non_existing_bucket(s *S3Conf) error { return actionHandler(s, testName, func(s3client *s3.Client, bucket string) error { ctx, cancel := context.WithTimeout(context.Background(), shortTimeout) _, err := s3client.DeleteBucketPolicy(ctx, &s3.DeleteBucketPolicyInput{ - Bucket: getPtr("non_existing_bucket"), + Bucket: getPtr("nonexistingbucket"), }) cancel()