From fb00dff83bc9ff4fb5e69384a7096e7cb0e8fd9f Mon Sep 17 00:00:00 2001 From: Pavel Pogodaev Date: Mon, 11 Nov 2024 14:22:58 +0300 Subject: [PATCH] [#540] Add md5 S3Tests compatability Signed-off-by: Pavel Pogodaev --- api/handler/delete.go | 2 +- api/handler/encryption_test.go | 28 ++++++++++++++++++++++++++++ api/handler/put.go | 12 +++++++++++- api/handler/put_test.go | 9 ++++++--- api/layer/layer.go | 2 +- api/layer/object.go | 9 ++++++--- 6 files changed, 53 insertions(+), 9 deletions(-) diff --git a/api/handler/delete.go b/api/handler/delete.go index 39769ffc..8ac9fa9f 100644 --- a/api/handler/delete.go +++ b/api/handler/delete.go @@ -246,7 +246,7 @@ func (h *handler) DeleteBucketHandler(w http.ResponseWriter, r *http.Request) { } if err = checkOwner(bktInfo, reqInfo.User); err != nil { - h.logAndSendError(w, "request owner id does not match bucket owner id", reqInfo, err) + h.logAndSendError(ctx, w, "request owner id does not match bucket owner id", reqInfo, err) return } diff --git a/api/handler/encryption_test.go b/api/handler/encryption_test.go index d43721de..3561c658 100644 --- a/api/handler/encryption_test.go +++ b/api/handler/encryption_test.go @@ -48,6 +48,25 @@ func TestSimpleGetEncrypted(t *testing.T) { require.Equal(t, content, string(response)) } +func TestMD5HeaderBadOrEmpty(t *testing.T) { + tc := prepareHandlerContext(t) + + bktName, objName := "bucket-for-sse-c", "object-to-encrypt" + createTestBucket(tc, bktName) + content := "content" + + headers := map[string]string{ + api.ContentMD5: "", + } + putEncryptedObjectWithHeadersErr(t, tc, bktName, objName, content, headers, errors.ErrInvalidDigest) + + headers = map[string]string{ + api.ContentMD5: "YWJjMTIzIT8kKiYoKSctPUB+", + } + + putEncryptedObjectWithHeadersErr(t, tc, bktName, objName, content, headers, errors.ErrBadDigest) +} + func TestGetEncryptedRange(t *testing.T) { tc := prepareHandlerContext(t) @@ -360,6 +379,15 @@ func putEncryptedObject(t *testing.T, tc *handlerContext, bktName, objName, cont assertStatus(t, w, http.StatusOK) } +func putEncryptedObjectWithHeadersErr(t *testing.T, tc *handlerContext, bktName, objName, content string, headers map[string]string, code errors.ErrorCode) { + body := bytes.NewReader([]byte(content)) + w, r := prepareTestPayloadRequest(tc, bktName, objName, body) + setHeaders(r, headers) + + tc.Handler().PutObjectHandler(w, r) + assertS3Error(t, w, errors.GetAPIError(code)) +} + func getEncryptedObject(hc *handlerContext, bktName, objName string) ([]byte, http.Header) { w, r := prepareTestRequest(hc, bktName, objName, nil) setEncryptHeaders(r) diff --git a/api/handler/put.go b/api/handler/put.go index 9e5a06a8..d08389f9 100644 --- a/api/handler/put.go +++ b/api/handler/put.go @@ -251,7 +251,7 @@ func (h *handler) PutObjectHandler(w http.ResponseWriter, r *http.Request) { Reader: body, Header: metadata, Encryption: encryptionParams, - ContentMD5: r.Header.Get(api.ContentMD5), + ContentMD5: getMD5Header(r), ContentSHA256Hash: r.Header.Get(api.AmzContentSha256), } @@ -1038,3 +1038,13 @@ func (h *handler) parseLocationConstraint(r *http.Request) (*createBucketParams, } return params, nil } + +func getMD5Header(r *http.Request) *string { + var md5Hdr *string + if len(r.Header.Values(api.ContentMD5)) != 0 { + hdr := r.Header.Get(api.ContentMD5) + md5Hdr = &hdr + } + + return md5Hdr +} diff --git a/api/handler/put_test.go b/api/handler/put_test.go index 235a5e58..f64123fe 100644 --- a/api/handler/put_test.go +++ b/api/handler/put_test.go @@ -284,6 +284,12 @@ func TestPutObjectWithInvalidContentMD5(t *testing.T) { w, r := prepareTestPayloadRequest(tc, bktName, objName, bytes.NewReader(content)) r.Header.Set(api.ContentMD5, base64.StdEncoding.EncodeToString([]byte("invalid"))) tc.Handler().PutObjectHandler(w, r) + assertS3Error(t, w, apierr.GetAPIError(apierr.ErrBadDigest)) + + content = []byte("content") + w, r = prepareTestPayloadRequest(tc, bktName, objName, bytes.NewReader(content)) + r.Header.Set(api.ContentMD5, base64.StdEncoding.EncodeToString([]byte(""))) + tc.Handler().PutObjectHandler(w, r) assertS3Error(t, w, apierr.GetAPIError(apierr.ErrInvalidDigest)) checkNotFound(t, tc, bktName, objName, emptyVersion) @@ -498,9 +504,6 @@ func getEmptyChunkedRequest(ctx context.Context, t *testing.T, bktName, objName AWSAccessKeyID := "48c1K4PLVb7SvmV3PjDKEuXaMh8yZMXZ8Wx9msrkKcYw06dZeaxeiPe8vyFm2WsoeVaNt7UWEjNsVkagDs8oX4XXh" AWSSecretAccessKey := "09260955b4eb0279dc017ba20a1ddac909cbd226c86cbb2d868e55534c8e64b0" - //awsCreds := credentials.NewStaticCredentials(AWSAccessKeyID, AWSSecretAccessKey, "") - //signer := v4.NewSigner(awsCreds) - reqBody := bytes.NewBufferString("0;chunk-signature=311a7142c8f3a07972c3aca65c36484b513a8fee48ab7178c7225388f2ae9894\r\n\r\n") req, err := http.NewRequest("PUT", "http://localhost:8084/"+bktName+"/"+objName, reqBody) diff --git a/api/layer/layer.go b/api/layer/layer.go index 0768c83b..12d064c1 100644 --- a/api/layer/layer.go +++ b/api/layer/layer.go @@ -111,7 +111,7 @@ type ( Encryption encryption.Params CopiesNumbers []uint32 CompleteMD5Hash string - ContentMD5 string + ContentMD5 *string ContentSHA256Hash string } diff --git a/api/layer/object.go b/api/layer/object.go index 82607401..8f4d64f1 100644 --- a/api/layer/object.go +++ b/api/layer/object.go @@ -286,8 +286,11 @@ func (n *Layer) PutObject(ctx context.Context, p *PutObjectParams) (*data.Extend return nil, err } - if !p.Encryption.Enabled() && len(p.ContentMD5) > 0 { - headerMd5Hash, err := base64.StdEncoding.DecodeString(p.ContentMD5) + if !p.Encryption.Enabled() && p.ContentMD5 != nil { + if len(*p.ContentMD5) == 0 { + return nil, apierr.GetAPIError(apierr.ErrInvalidDigest) + } + headerMd5Hash, err := base64.StdEncoding.DecodeString(*p.ContentMD5) if err != nil { return nil, apierr.GetAPIError(apierr.ErrInvalidDigest) } @@ -296,7 +299,7 @@ func (n *Layer) PutObject(ctx context.Context, p *PutObjectParams) (*data.Extend if err != nil { n.reqLogger(ctx).Debug(logs.FailedToDeleteObject, zap.Stringer("cid", p.BktInfo.CID), zap.Stringer("oid", createdObj.ID)) } - return nil, apierr.GetAPIError(apierr.ErrInvalidDigest) + return nil, apierr.GetAPIError(apierr.ErrBadDigest) } }