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)
}
}