fix: reject uploads with uploadId for every bucket and object operation
Requests carrying both the uploads and uploadId query parameters were only rejected for a bucket GET, so DELETE, PUT, POST and HEAD on the bucket or object paths still ran real operations. S3 rejects the combination for every method on both paths, before authentication and before checking that the bucket exists. Register the error route for all methods on the bucket and object routers right after the CORS middleware is set up, ahead of every other route, and cover each method and path with an integration test.
This commit is contained in:
1 parent
47b43ba5ea
commit
5d293b1316
3 files changed
+55
-5
No files matched your search
+11
-5
@@ -102,6 +102,17 @@ func (sa *S3ApiRouter) Init() {
|
|||||||
objectRouter := sa.app.Group("/:bucket/*")
|
objectRouter := sa.app.Group("/:bucket/*")
|
||||||
applyBucketCORS := middlewares.ApplyBucketCORS(sa.be, middlewares.BucketFromPath, sa.corsAllowOrigin)
|
applyBucketCORS := middlewares.ApplyBucketCORS(sa.be, middlewares.BucketFromPath, sa.corsAllowOrigin)
|
||||||
|
|
||||||
|
// '?uploads' together with '?uploadId' is rejected for every
|
||||||
|
// bucket and object operation
|
||||||
|
for _, method := range []string{http.MethodGet, http.MethodHead, http.MethodPut, http.MethodPost, http.MethodDelete} {
|
||||||
|
for _, router := range []fiber.Router{bucketRouter, objectRouter} {
|
||||||
|
router.Add([]string{method}, "",
|
||||||
|
middlewares.MatchQueryArgs("uploads", "uploadId"),
|
||||||
|
controllers.ProcessHandlers(ctrl.HandleErrorRoute(s3err.GetInvalidArgumentErr(s3err.InvalidArgUploadIdWithUploads, "uploadId")), metrics.ActionUndetected, services),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// PUT bucket operations
|
// PUT bucket operations
|
||||||
bucketRouter.Put("",
|
bucketRouter.Put("",
|
||||||
middlewares.MatchQueryArgs("tagging"),
|
middlewares.MatchQueryArgs("tagging"),
|
||||||
@@ -725,11 +736,6 @@ func (sa *S3ApiRouter) Init() {
|
|||||||
middlewares.VerifyV4Signature(sa.root, sa.iam, sa.region, false, false, false),
|
middlewares.VerifyV4Signature(sa.root, sa.iam, sa.region, false, false, false),
|
||||||
middlewares.ParseAcl(sa.be),
|
middlewares.ParseAcl(sa.be),
|
||||||
))
|
))
|
||||||
// bucket operation with both '?uploads' and '?uploadId' is rejected
|
|
||||||
bucketRouter.Get("",
|
|
||||||
middlewares.MatchQueryArgs("uploads", "uploadId"),
|
|
||||||
controllers.ProcessHandlers(ctrl.HandleErrorRoute(s3err.GetInvalidArgumentErr(s3err.InvalidArgUploadIdWithUploads, "uploadId")), metrics.ActionUndetected, services),
|
|
||||||
)
|
|
||||||
bucketRouter.Get("",
|
bucketRouter.Get("",
|
||||||
middlewares.MatchQueryArgs("uploads"),
|
middlewares.MatchQueryArgs("uploads"),
|
||||||
controllers.ProcessHandlers(
|
controllers.ProcessHandlers(
|
||||||
|
|||||||
@@ -195,6 +195,48 @@ func RouterCopySourceNotAllowed(s *S3Conf) error {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func RouterUploadsWithUploadId(s *S3Conf) error {
|
||||||
|
testName := "RouterUploadsWithUploadId"
|
||||||
|
return actionHandlerNoSetup(s, testName, func(s3client *s3.Client, bucket string) error {
|
||||||
|
for _, method := range []string{
|
||||||
|
http.MethodGet,
|
||||||
|
http.MethodHead,
|
||||||
|
http.MethodPut,
|
||||||
|
http.MethodPost,
|
||||||
|
http.MethodDelete,
|
||||||
|
} {
|
||||||
|
for _, path := range []string{
|
||||||
|
"/bucket?uploads&uploadId=something",
|
||||||
|
"/bucket/object?uploads&uploadId=something",
|
||||||
|
} {
|
||||||
|
req, err := http.NewRequest(method, s.endpoint+path, nil)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to make %s request to %s", method, path)
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := s.httpClient.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to send %s request to %s", method, path)
|
||||||
|
}
|
||||||
|
|
||||||
|
if method == http.MethodHead {
|
||||||
|
// for head requests only check the status code
|
||||||
|
if resp.StatusCode != http.StatusBadRequest {
|
||||||
|
return fmt.Errorf("expected 400 status code for HEAD %s request, instead got %v", path, resp.StatusCode)
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := checkHTTPResponseApiErr(resp, s3err.GetInvalidArgumentErr(s3err.InvalidArgUploadIdWithUploads, "uploadId")); err != nil {
|
||||||
|
return fmt.Errorf("%s %s: %w", method, path, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func RouterListVersionsWithKey(s *S3Conf) error {
|
func RouterListVersionsWithKey(s *S3Conf) error {
|
||||||
testName := "RouterListVersionsWithKey"
|
testName := "RouterListVersionsWithKey"
|
||||||
return actionHandlerNoSetup(s, testName, func(s3client *s3.Client, bucket string) error {
|
return actionHandlerNoSetup(s, testName, func(s3client *s3.Client, bucket string) error {
|
||||||
|
|||||||
@@ -2191,6 +2191,7 @@ func TestRouter(ts *TestState) {
|
|||||||
ts.Run(RouterGetUploadsWithKey)
|
ts.Run(RouterGetUploadsWithKey)
|
||||||
ts.Run(RouterCopySourceNotAllowed)
|
ts.Run(RouterCopySourceNotAllowed)
|
||||||
ts.Run(RouterListVersionsWithKey)
|
ts.Run(RouterListVersionsWithKey)
|
||||||
|
ts.Run(RouterUploadsWithUploadId)
|
||||||
ts.Run(RouterObjectAnnotationNotImplemented)
|
ts.Run(RouterObjectAnnotationNotImplemented)
|
||||||
ts.Run(RouterRenameObjectNotImplemented)
|
ts.Run(RouterRenameObjectNotImplemented)
|
||||||
ts.Run(RouterObjectTorrentMethodNotAllowed)
|
ts.Run(RouterObjectTorrentMethodNotAllowed)
|
||||||
@@ -3794,6 +3795,7 @@ func GetIntTests() IntTests {
|
|||||||
"RouterGetUploadsWithKey": RouterGetUploadsWithKey,
|
"RouterGetUploadsWithKey": RouterGetUploadsWithKey,
|
||||||
"RouterCopySourceNotAllowed": RouterCopySourceNotAllowed,
|
"RouterCopySourceNotAllowed": RouterCopySourceNotAllowed,
|
||||||
"RouterListVersionsWithKey": RouterListVersionsWithKey,
|
"RouterListVersionsWithKey": RouterListVersionsWithKey,
|
||||||
|
"RouterUploadsWithUploadId": RouterUploadsWithUploadId,
|
||||||
"RouterObjectAnnotationNotImplemented": RouterObjectAnnotationNotImplemented,
|
"RouterObjectAnnotationNotImplemented": RouterObjectAnnotationNotImplemented,
|
||||||
"RouterRenameObjectNotImplemented": RouterRenameObjectNotImplemented,
|
"RouterRenameObjectNotImplemented": RouterRenameObjectNotImplemented,
|
||||||
"RouterObjectTorrentMethodNotAllowed": RouterObjectTorrentMethodNotAllowed,
|
"RouterObjectTorrentMethodNotAllowed": RouterObjectTorrentMethodNotAllowed,
|
||||||
|
|||||||
Reference in new issue
Block a user