mirror of https://github.com/minio/minio.git
object-handler: skip sha256 calculation if x-amz-content-sha256=="UNSIGNED-PAYLOAD" (#2038)
fixes #2024 #2056
This commit is contained in:
parent
734e779b19
commit
eb5f782c74
|
@ -27,6 +27,15 @@ import (
|
|||
"strings"
|
||||
)
|
||||
|
||||
// http Header "x-amz-content-sha256" == "UNSIGNED-PAYLOAD" indicates that the
|
||||
// client did not calculate sha256 of the payload.
|
||||
const unsignedPayload = "UNSIGNED-PAYLOAD"
|
||||
|
||||
// Verify if the request http Header "x-amz-content-sha256" == "UNSIGNED-PAYLOAD"
|
||||
func isRequestUnsignedPayload(r *http.Request) bool {
|
||||
return r.Header.Get("x-amz-content-sha256") == unsignedPayload
|
||||
}
|
||||
|
||||
// Verify if request has JWT.
|
||||
func isRequestJWT(r *http.Request) bool {
|
||||
if _, ok := r.Header["Authorization"]; ok {
|
||||
|
@ -126,10 +135,16 @@ func isReqAuthenticated(r *http.Request) (s3Error APIErrorCode) {
|
|||
// Populate back the payload.
|
||||
r.Body = ioutil.NopCloser(bytes.NewReader(payload))
|
||||
validateRegion := true // Validate region.
|
||||
var sha256sum string
|
||||
if skipSHA256Calculation(r) {
|
||||
sha256sum = unsignedPayload
|
||||
} else {
|
||||
sha256sum = hex.EncodeToString(sum256(payload))
|
||||
}
|
||||
if isRequestSignatureV4(r) {
|
||||
return doesSignatureMatch(hex.EncodeToString(sum256(payload)), r, validateRegion)
|
||||
return doesSignatureMatch(sha256sum, r, validateRegion)
|
||||
} else if isRequestPresignedSignatureV4(r) {
|
||||
return doesPresignedSignatureMatch(hex.EncodeToString(sum256(payload)), r, validateRegion)
|
||||
return doesPresignedSignatureMatch(sha256sum, r, validateRegion)
|
||||
}
|
||||
return ErrAccessDenied
|
||||
}
|
||||
|
|
|
@ -51,6 +51,14 @@ func setGetRespHeaders(w http.ResponseWriter, reqParams url.Values) {
|
|||
}
|
||||
}
|
||||
|
||||
// http Header "x-amz-content-sha256" == "UNSIGNED-PAYLOAD" indicates that the
|
||||
// client did not calculate sha256 of the payload. Hence we skip calculating sha256.
|
||||
// We also skip calculating sha256 for presigned requests without "x-amz-content-sha256" header.
|
||||
func skipSHA256Calculation(r *http.Request) bool {
|
||||
shaHeader := r.Header.Get("X-Amz-Content-Sha256")
|
||||
return isRequestUnsignedPayload(r) || (isRequestPresignedSignatureV4(r) && shaHeader == "")
|
||||
}
|
||||
|
||||
// errAllowableNotFound - For an anon user, return 404 if have ListBucket, 403 otherwise
|
||||
// this is in keeping with the permissions sections of the docs of both:
|
||||
// HEAD Object: http://docs.aws.amazon.com/AmazonS3/latest/API/RESTObjectHEAD.html
|
||||
|
@ -594,51 +602,73 @@ func (api objectAPIHandlers) PutObjectHandler(w http.ResponseWriter, r *http.Req
|
|||
// Create anonymous object.
|
||||
md5Sum, err = api.ObjectAPI.PutObject(bucket, object, size, r.Body, metadata)
|
||||
case authTypePresigned, authTypeSigned:
|
||||
// Initialize a pipe for data pipe line.
|
||||
reader, writer := io.Pipe()
|
||||
var wg = &sync.WaitGroup{}
|
||||
// Start writing in a routine.
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
shaWriter := sha256.New()
|
||||
multiWriter := io.MultiWriter(shaWriter, writer)
|
||||
if _, wErr := io.CopyN(multiWriter, r.Body, size); wErr != nil {
|
||||
// Pipe closed.
|
||||
if wErr == io.ErrClosedPipe {
|
||||
return
|
||||
}
|
||||
errorIf(wErr, "Unable to read from HTTP body.")
|
||||
writer.CloseWithError(wErr)
|
||||
return
|
||||
}
|
||||
shaPayload := shaWriter.Sum(nil)
|
||||
validateRegion := true // Validate region.
|
||||
validateRegion := true // Validate region.
|
||||
|
||||
if skipSHA256Calculation(r) {
|
||||
// Either sha256-header is "UNSIGNED-PAYLOAD" or this is a presigned PUT
|
||||
// request without sha256-header.
|
||||
var s3Error APIErrorCode
|
||||
if isRequestSignatureV4(r) {
|
||||
s3Error = doesSignatureMatch(hex.EncodeToString(shaPayload), r, validateRegion)
|
||||
s3Error = doesSignatureMatch(unsignedPayload, r, validateRegion)
|
||||
} else if isRequestPresignedSignatureV4(r) {
|
||||
s3Error = doesPresignedSignatureMatch(hex.EncodeToString(shaPayload), r, validateRegion)
|
||||
s3Error = doesPresignedSignatureMatch(unsignedPayload, r, validateRegion)
|
||||
}
|
||||
var sErr error
|
||||
if s3Error != ErrNone {
|
||||
if s3Error == ErrSignatureDoesNotMatch {
|
||||
sErr = errSignatureMismatch
|
||||
err = errSignatureMismatch
|
||||
} else {
|
||||
sErr = fmt.Errorf("%v", getAPIError(s3Error))
|
||||
err = fmt.Errorf("%v", getAPIError(s3Error))
|
||||
}
|
||||
writer.CloseWithError(sErr)
|
||||
return
|
||||
} else {
|
||||
md5Sum, err = api.ObjectAPI.PutObject(bucket, object, size, r.Body, metadata)
|
||||
}
|
||||
writer.Close()
|
||||
}()
|
||||
} else {
|
||||
// Sha256 of payload has to be calculated and matched with what was sent in the header.
|
||||
// Initialize a pipe for data pipe line.
|
||||
reader, writer := io.Pipe()
|
||||
var wg = &sync.WaitGroup{}
|
||||
// Start writing in a routine.
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
shaWriter := sha256.New()
|
||||
multiWriter := io.MultiWriter(shaWriter, writer)
|
||||
if _, wErr := io.CopyN(multiWriter, r.Body, size); wErr != nil {
|
||||
// Pipe closed.
|
||||
if wErr == io.ErrClosedPipe {
|
||||
return
|
||||
}
|
||||
errorIf(wErr, "Unable to read from HTTP body.")
|
||||
writer.CloseWithError(wErr)
|
||||
return
|
||||
}
|
||||
shaPayload := shaWriter.Sum(nil)
|
||||
var s3Error APIErrorCode
|
||||
if isRequestSignatureV4(r) {
|
||||
s3Error = doesSignatureMatch(hex.EncodeToString(shaPayload), r, validateRegion)
|
||||
} else if isRequestPresignedSignatureV4(r) {
|
||||
s3Error = doesPresignedSignatureMatch(hex.EncodeToString(shaPayload), r, validateRegion)
|
||||
}
|
||||
var sErr error
|
||||
if s3Error != ErrNone {
|
||||
if s3Error == ErrSignatureDoesNotMatch {
|
||||
sErr = errSignatureMismatch
|
||||
} else {
|
||||
sErr = fmt.Errorf("%v", getAPIError(s3Error))
|
||||
}
|
||||
writer.CloseWithError(sErr)
|
||||
return
|
||||
}
|
||||
writer.Close()
|
||||
}()
|
||||
|
||||
// Create object.
|
||||
md5Sum, err = api.ObjectAPI.PutObject(bucket, object, size, reader, metadata)
|
||||
// Close the pipe.
|
||||
reader.Close()
|
||||
// Wait for all the routines to finish.
|
||||
wg.Wait()
|
||||
// Create object.
|
||||
md5Sum, err = api.ObjectAPI.PutObject(bucket, object, size, reader, metadata)
|
||||
// Close the pipe.
|
||||
reader.Close()
|
||||
// Wait for all the routines to finish.
|
||||
wg.Wait()
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
errorIf(err, "Unable to create an object.")
|
||||
|
@ -765,31 +795,16 @@ func (api objectAPIHandlers) PutObjectPartHandler(w http.ResponseWriter, r *http
|
|||
hexMD5 := hex.EncodeToString(md5Bytes)
|
||||
partMD5, err = api.ObjectAPI.PutObjectPart(bucket, object, uploadID, partID, size, r.Body, hexMD5)
|
||||
case authTypePresigned, authTypeSigned:
|
||||
// Initialize a pipe for data pipe line.
|
||||
reader, writer := io.Pipe()
|
||||
var wg = &sync.WaitGroup{}
|
||||
// Start writing in a routine.
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
shaWriter := sha256.New()
|
||||
multiWriter := io.MultiWriter(shaWriter, writer)
|
||||
if _, wErr := io.CopyN(multiWriter, r.Body, size); wErr != nil {
|
||||
// Pipe closed, just ignore it.
|
||||
if wErr == io.ErrClosedPipe {
|
||||
return
|
||||
}
|
||||
errorIf(wErr, "Unable to read from HTTP request body.")
|
||||
writer.CloseWithError(wErr)
|
||||
return
|
||||
}
|
||||
shaPayload := shaWriter.Sum(nil)
|
||||
validateRegion := true // Validate region.
|
||||
validateRegion := true // Validate region.
|
||||
|
||||
if skipSHA256Calculation(r) {
|
||||
// Either sha256-header is "UNSIGNED-PAYLOAD" or this is a presigned
|
||||
// request without sha256-header.
|
||||
var s3Error APIErrorCode
|
||||
if isRequestSignatureV4(r) {
|
||||
s3Error = doesSignatureMatch(hex.EncodeToString(shaPayload), r, validateRegion)
|
||||
s3Error = doesSignatureMatch(unsignedPayload, r, validateRegion)
|
||||
} else if isRequestPresignedSignatureV4(r) {
|
||||
s3Error = doesPresignedSignatureMatch(hex.EncodeToString(shaPayload), r, validateRegion)
|
||||
s3Error = doesPresignedSignatureMatch(unsignedPayload, r, validateRegion)
|
||||
}
|
||||
if s3Error != ErrNone {
|
||||
if s3Error == ErrSignatureDoesNotMatch {
|
||||
|
@ -797,18 +812,55 @@ func (api objectAPIHandlers) PutObjectPartHandler(w http.ResponseWriter, r *http
|
|||
} else {
|
||||
err = fmt.Errorf("%v", getAPIError(s3Error))
|
||||
}
|
||||
writer.CloseWithError(err)
|
||||
return
|
||||
} else {
|
||||
md5SumHex := hex.EncodeToString(md5Bytes)
|
||||
partMD5, err = api.ObjectAPI.PutObjectPart(bucket, object, uploadID, partID, size, r.Body, md5SumHex)
|
||||
}
|
||||
// Close the writer.
|
||||
writer.Close()
|
||||
}()
|
||||
md5SumHex := hex.EncodeToString(md5Bytes)
|
||||
partMD5, err = api.ObjectAPI.PutObjectPart(bucket, object, uploadID, partID, size, reader, md5SumHex)
|
||||
// Close the pipe.
|
||||
reader.Close()
|
||||
// Wait for all the routines to finish.
|
||||
wg.Wait()
|
||||
} else {
|
||||
// Initialize a pipe for data pipe line.
|
||||
reader, writer := io.Pipe()
|
||||
var wg = &sync.WaitGroup{}
|
||||
// Start writing in a routine.
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
shaWriter := sha256.New()
|
||||
multiWriter := io.MultiWriter(shaWriter, writer)
|
||||
if _, wErr := io.CopyN(multiWriter, r.Body, size); wErr != nil {
|
||||
// Pipe closed, just ignore it.
|
||||
if wErr == io.ErrClosedPipe {
|
||||
return
|
||||
}
|
||||
errorIf(wErr, "Unable to read from HTTP request body.")
|
||||
writer.CloseWithError(wErr)
|
||||
return
|
||||
}
|
||||
shaPayload := shaWriter.Sum(nil)
|
||||
var s3Error APIErrorCode
|
||||
if isRequestSignatureV4(r) {
|
||||
s3Error = doesSignatureMatch(hex.EncodeToString(shaPayload), r, validateRegion)
|
||||
} else if isRequestPresignedSignatureV4(r) {
|
||||
s3Error = doesPresignedSignatureMatch(hex.EncodeToString(shaPayload), r, validateRegion)
|
||||
}
|
||||
if s3Error != ErrNone {
|
||||
if s3Error == ErrSignatureDoesNotMatch {
|
||||
err = errSignatureMismatch
|
||||
} else {
|
||||
err = fmt.Errorf("%v", getAPIError(s3Error))
|
||||
}
|
||||
writer.CloseWithError(err)
|
||||
return
|
||||
}
|
||||
// Close the writer.
|
||||
writer.Close()
|
||||
}()
|
||||
md5SumHex := hex.EncodeToString(md5Bytes)
|
||||
partMD5, err = api.ObjectAPI.PutObjectPart(bucket, object, uploadID, partID, size, reader, md5SumHex)
|
||||
// Close the pipe.
|
||||
reader.Close()
|
||||
// Wait for all the routines to finish.
|
||||
wg.Wait()
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
errorIf(err, "Unable to create object part.")
|
||||
|
|
Loading…
Reference in New Issue