mirror of
https://github.com/minio/minio.git
synced 2025-02-28 05:49:16 -05:00
Fix CopyObjectPart broken source encryption support (#6699)
Current master didn't support CopyObjectPart when source was encrypted, this PR fixes this by allowing range CopySource decryption at different sequence numbers. Fixes #6698
This commit is contained in:
parent
bab4c90c45
commit
555d54371c
@ -332,7 +332,7 @@ func DecryptRequestWithSequenceNumberR(client io.Reader, h http.Header, bucket,
|
|||||||
|
|
||||||
// DecryptCopyRequestR - same as DecryptCopyRequest, but with a
|
// DecryptCopyRequestR - same as DecryptCopyRequest, but with a
|
||||||
// Reader
|
// Reader
|
||||||
func DecryptCopyRequestR(client io.Reader, h http.Header, bucket, object string, metadata map[string]string) (io.Reader, error) {
|
func DecryptCopyRequestR(client io.Reader, h http.Header, bucket, object string, seqNumber uint32, metadata map[string]string) (io.Reader, error) {
|
||||||
var (
|
var (
|
||||||
key []byte
|
key []byte
|
||||||
err error
|
err error
|
||||||
@ -343,7 +343,7 @@ func DecryptCopyRequestR(client io.Reader, h http.Header, bucket, object string,
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return newDecryptReader(client, key, bucket, object, 0, metadata)
|
return newDecryptReader(client, key, bucket, object, seqNumber, metadata)
|
||||||
}
|
}
|
||||||
|
|
||||||
func newDecryptReader(client io.Reader, key []byte, bucket, object string, seqNumber uint32, metadata map[string]string) (io.Reader, error) {
|
func newDecryptReader(client io.Reader, key []byte, bucket, object string, seqNumber uint32, metadata map[string]string) (io.Reader, error) {
|
||||||
@ -365,17 +365,6 @@ func newDecryptReaderWithObjectKey(client io.Reader, objectEncryptionKey []byte,
|
|||||||
return reader, nil
|
return reader, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetEncryptedOffsetLength - returns encrypted offset and length
|
|
||||||
// along with sequence number
|
|
||||||
func GetEncryptedOffsetLength(startOffset, length int64, objInfo ObjectInfo) (seqNumber uint32, encStartOffset, encLength int64) {
|
|
||||||
if !isEncryptedMultipart(objInfo) {
|
|
||||||
seqNumber, encStartOffset, encLength = getEncryptedSinglePartOffsetLength(startOffset, length, objInfo)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
seqNumber, encStartOffset, encLength = getEncryptedMultipartsOffsetLength(startOffset, length, objInfo)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// DecryptBlocksRequestR - same as DecryptBlocksRequest but with a
|
// DecryptBlocksRequestR - same as DecryptBlocksRequest but with a
|
||||||
// reader
|
// reader
|
||||||
func DecryptBlocksRequestR(inputReader io.Reader, h http.Header, offset,
|
func DecryptBlocksRequestR(inputReader io.Reader, h http.Header, offset,
|
||||||
@ -389,7 +378,7 @@ func DecryptBlocksRequestR(inputReader io.Reader, h http.Header, offset,
|
|||||||
var reader io.Reader
|
var reader io.Reader
|
||||||
var err error
|
var err error
|
||||||
if copySource {
|
if copySource {
|
||||||
reader, err = DecryptCopyRequestR(inputReader, h, bucket, object, oi.UserDefined)
|
reader, err = DecryptCopyRequestR(inputReader, h, bucket, object, seqNumber, oi.UserDefined)
|
||||||
} else {
|
} else {
|
||||||
reader, err = DecryptRequestWithSequenceNumberR(inputReader, h, bucket, object, seqNumber, oi.UserDefined)
|
reader, err = DecryptRequestWithSequenceNumberR(inputReader, h, bucket, object, seqNumber, oi.UserDefined)
|
||||||
}
|
}
|
||||||
|
@ -701,30 +701,12 @@ func (api objectAPIHandlers) CopyObjectHandler(w http.ResponseWriter, r *http.Re
|
|||||||
getObjectNInfo = api.CacheAPI().GetObjectNInfo
|
getObjectNInfo = api.CacheAPI().GetObjectNInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get request range.
|
|
||||||
var rs *HTTPRangeSpec
|
|
||||||
rangeHeader := r.Header.Get("x-amz-copy-source-range")
|
|
||||||
if rangeHeader != "" {
|
|
||||||
var parseRangeErr error
|
|
||||||
if rs, parseRangeErr = parseRequestRangeSpec(rangeHeader); parseRangeErr != nil {
|
|
||||||
// Handle only errInvalidRange. Ignore other
|
|
||||||
// parse error and treat it as regular Get
|
|
||||||
// request like Amazon S3.
|
|
||||||
if parseRangeErr == errInvalidRange {
|
|
||||||
writeErrorResponse(w, ErrInvalidRange, r.URL)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// log the error.
|
|
||||||
logger.LogIf(ctx, parseRangeErr)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var lock = noLock
|
var lock = noLock
|
||||||
if !cpSrcDstSame {
|
if !cpSrcDstSame {
|
||||||
lock = readLock
|
lock = readLock
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var rs *HTTPRangeSpec
|
||||||
gr, err := getObjectNInfo(ctx, srcBucket, srcObject, rs, r.Header, lock, srcOpts)
|
gr, err := getObjectNInfo(ctx, srcBucket, srcObject, rs, r.Header, lock, srcOpts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
writeErrorResponse(w, toAPIErrorCode(err), r.URL)
|
writeErrorResponse(w, toAPIErrorCode(err), r.URL)
|
||||||
@ -1485,8 +1467,11 @@ func (api objectAPIHandlers) CopyObjectPartHandler(w http.ResponseWriter, r *htt
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get the object offset & length
|
// Get the object offset & length
|
||||||
startOffset, length, _ := rs.GetOffsetLength(actualPartSize)
|
startOffset, length, err := rs.GetOffsetLength(actualPartSize)
|
||||||
actualPartSize = length
|
if err != nil {
|
||||||
|
writeErrorResponse(w, toAPIErrorCode(err), r.URL)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
/// maximum copy size for multipart objects in a single operation
|
/// maximum copy size for multipart objects in a single operation
|
||||||
if isMaxAllowedPartSize(length) {
|
if isMaxAllowedPartSize(length) {
|
||||||
@ -1494,8 +1479,8 @@ func (api objectAPIHandlers) CopyObjectPartHandler(w http.ResponseWriter, r *htt
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
actualPartSize = length
|
||||||
var reader io.Reader
|
var reader io.Reader
|
||||||
var getLength = length
|
|
||||||
|
|
||||||
var li ListPartsInfo
|
var li ListPartsInfo
|
||||||
li, err = objectAPI.ListObjectParts(ctx, dstBucket, dstObject, uploadID, 0, 1)
|
li, err = objectAPI.ListObjectParts(ctx, dstBucket, dstObject, uploadID, 0, 1)
|
||||||
@ -1503,6 +1488,7 @@ func (api objectAPIHandlers) CopyObjectPartHandler(w http.ResponseWriter, r *htt
|
|||||||
writeErrorResponse(w, toAPIErrorCode(err), r.URL)
|
writeErrorResponse(w, toAPIErrorCode(err), r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read compression metadata preserved in the init multipart for the decision.
|
// Read compression metadata preserved in the init multipart for the decision.
|
||||||
_, compressPart := li.UserDefined[ReservedMetadataPrefix+"compression"]
|
_, compressPart := li.UserDefined[ReservedMetadataPrefix+"compression"]
|
||||||
isCompressed := compressPart
|
isCompressed := compressPart
|
||||||
@ -1535,7 +1521,7 @@ func (api objectAPIHandlers) CopyObjectPartHandler(w http.ResponseWriter, r *htt
|
|||||||
|
|
||||||
if objectAPI.IsEncryptionSupported() && !isCompressed {
|
if objectAPI.IsEncryptionSupported() && !isCompressed {
|
||||||
if crypto.IsEncrypted(li.UserDefined) {
|
if crypto.IsEncrypted(li.UserDefined) {
|
||||||
if !hasServerSideEncryptionHeader(r.Header) {
|
if !crypto.SSEC.IsRequested(r.Header) && crypto.SSEC.IsEncrypted(li.UserDefined) {
|
||||||
writeErrorResponse(w, ErrSSEMultipartEncrypted, r.URL)
|
writeErrorResponse(w, ErrSSEMultipartEncrypted, r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -1567,18 +1553,18 @@ func (api objectAPIHandlers) CopyObjectPartHandler(w http.ResponseWriter, r *htt
|
|||||||
}
|
}
|
||||||
|
|
||||||
info := ObjectInfo{Size: length}
|
info := ObjectInfo{Size: length}
|
||||||
size := info.EncryptedSize()
|
srcInfo.Reader, err = hash.NewReader(reader, info.EncryptedSize(), "", "", length)
|
||||||
srcInfo.Reader, err = hash.NewReader(reader, size, "", "", actualPartSize)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
writeErrorResponse(w, toAPIErrorCode(err), r.URL)
|
writeErrorResponse(w, toAPIErrorCode(err), r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy source object to destination, if source and destination
|
// Copy source object to destination, if source and destination
|
||||||
// object is same then only metadata is updated.
|
// object is same then only metadata is updated.
|
||||||
partInfo, err := objectAPI.CopyObjectPart(ctx, srcBucket, srcObject, dstBucket,
|
partInfo, err := objectAPI.CopyObjectPart(ctx, srcBucket, srcObject, dstBucket, dstObject, uploadID, partID,
|
||||||
dstObject, uploadID, partID, startOffset, getLength, srcInfo, srcOpts, dstOpts)
|
startOffset, length, srcInfo, srcOpts, dstOpts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
writeErrorResponse(w, toAPIErrorCode(err), r.URL)
|
writeErrorResponse(w, toAPIErrorCode(err), r.URL)
|
||||||
return
|
return
|
||||||
|
Loading…
x
Reference in New Issue
Block a user