mirror of
https://github.com/minio/minio.git
synced 2024-12-23 21:55:53 -05:00
signature: Region changes should be handled just like AWS. (#2805)
- PutBucket happens with 'us-east-1'. - ListBuckets happens with any region. - GetBucketLocation happens with 'us-east-1' and location is returned.
This commit is contained in:
parent
5fdd768903
commit
64083b9227
@ -28,7 +28,7 @@ type ObjectIdentifier struct {
|
||||
// createBucketConfiguration container for bucket configuration request from client.
|
||||
// Used for parsing the location from the request body for MakeBucketbucket.
|
||||
type createBucketLocationConfiguration struct {
|
||||
XMLName xml.Name `xml:"http://s3.amazonaws.com/doc/2006-03-01/ CreateBucketConfiguration" json:"-"`
|
||||
XMLName xml.Name `xml:"CreateBucketConfiguration" json:"-"`
|
||||
Location string `xml:"LocationConstraint"`
|
||||
}
|
||||
|
||||
|
@ -105,7 +105,7 @@ func sumMD5(data []byte) []byte {
|
||||
}
|
||||
|
||||
// Verify if request has valid AWS Signature Version '4'.
|
||||
func isReqAuthenticated(r *http.Request) (s3Error APIErrorCode) {
|
||||
func isReqAuthenticated(r *http.Request, region string) (s3Error APIErrorCode) {
|
||||
if r == nil {
|
||||
return ErrInternalError
|
||||
}
|
||||
@ -121,7 +121,6 @@ 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
|
||||
// Skips calculating sha256 on the payload on server,
|
||||
// if client requested for it.
|
||||
@ -131,9 +130,9 @@ func isReqAuthenticated(r *http.Request) (s3Error APIErrorCode) {
|
||||
sha256sum = hex.EncodeToString(sum256(payload))
|
||||
}
|
||||
if isRequestSignatureV4(r) {
|
||||
return doesSignatureMatch(sha256sum, r, validateRegion)
|
||||
return doesSignatureMatch(sha256sum, r, region)
|
||||
} else if isRequestPresignedSignatureV4(r) {
|
||||
return doesPresignedSignatureMatch(sha256sum, r, validateRegion)
|
||||
return doesPresignedSignatureMatch(sha256sum, r, region)
|
||||
}
|
||||
return ErrAccessDenied
|
||||
}
|
||||
@ -145,13 +144,19 @@ func isReqAuthenticated(r *http.Request) (s3Error APIErrorCode) {
|
||||
// request headers and body are used to calculate the signature validating
|
||||
// the client signature present in request.
|
||||
func checkAuth(r *http.Request) APIErrorCode {
|
||||
// Validates the request for both Presigned and Signed
|
||||
return checkAuthWithRegion(r, serverConfig.GetRegion())
|
||||
}
|
||||
|
||||
// checkAuthWithRegion - similar to checkAuth but takes a custom region.
|
||||
func checkAuthWithRegion(r *http.Request, region string) APIErrorCode {
|
||||
// Validates the request for both Presigned and Signed.
|
||||
aType := getRequestAuthType(r)
|
||||
if aType != authTypePresigned && aType != authTypeSigned {
|
||||
// For all unhandled auth types return error AccessDenied.
|
||||
return ErrAccessDenied
|
||||
}
|
||||
// Validates the request for both Presigned and Signed.
|
||||
return isReqAuthenticated(r)
|
||||
return isReqAuthenticated(r, region)
|
||||
}
|
||||
|
||||
// authHandler - handles all the incoming authorization headers and validates them if possible.
|
||||
|
@ -294,7 +294,7 @@ func TestIsReqAuthenticated(t *testing.T) {
|
||||
if testCase.s3Error == ErrBadDigest {
|
||||
testCase.req.Header.Set("Content-Md5", "garbage")
|
||||
}
|
||||
if s3Error := isReqAuthenticated(testCase.req); s3Error != testCase.s3Error {
|
||||
if s3Error := isReqAuthenticated(testCase.req, serverConfig.GetRegion()); s3Error != testCase.s3Error {
|
||||
t.Fatalf("Unexpected s3error returned wanted %d, got %d", testCase.s3Error, s3Error)
|
||||
}
|
||||
}
|
||||
|
@ -82,7 +82,7 @@ func (api objectAPIHandlers) ListObjectsV2Handler(w http.ResponseWriter, r *http
|
||||
return
|
||||
}
|
||||
case authTypeSigned, authTypePresigned:
|
||||
if s3Error := isReqAuthenticated(r); s3Error != ErrNone {
|
||||
if s3Error := isReqAuthenticated(r, serverConfig.GetRegion()); s3Error != ErrNone {
|
||||
errorIf(errSignatureMismatch, dumpRequest(r))
|
||||
writeErrorResponse(w, r, s3Error, r.URL.Path)
|
||||
return
|
||||
@ -149,7 +149,7 @@ func (api objectAPIHandlers) ListObjectsV1Handler(w http.ResponseWriter, r *http
|
||||
return
|
||||
}
|
||||
case authTypeSigned, authTypePresigned:
|
||||
if s3Error := isReqAuthenticated(r); s3Error != ErrNone {
|
||||
if s3Error := isReqAuthenticated(r, serverConfig.GetRegion()); s3Error != ErrNone {
|
||||
errorIf(errSignatureMismatch, dumpRequest(r))
|
||||
writeErrorResponse(w, r, s3Error, r.URL.Path)
|
||||
return
|
||||
|
@ -94,7 +94,7 @@ func (api objectAPIHandlers) GetBucketLocationHandler(w http.ResponseWriter, r *
|
||||
return
|
||||
}
|
||||
case authTypeSigned, authTypePresigned:
|
||||
if s3Error := isReqAuthenticated(r); s3Error != ErrNone {
|
||||
if s3Error := isReqAuthenticated(r, "us-east-1"); s3Error != ErrNone {
|
||||
errorIf(errSignatureMismatch, dumpRequest(r))
|
||||
writeErrorResponse(w, r, s3Error, r.URL.Path)
|
||||
return
|
||||
@ -150,7 +150,7 @@ func (api objectAPIHandlers) ListMultipartUploadsHandler(w http.ResponseWriter,
|
||||
return
|
||||
}
|
||||
case authTypePresigned, authTypeSigned:
|
||||
if s3Error := isReqAuthenticated(r); s3Error != ErrNone {
|
||||
if s3Error := isReqAuthenticated(r, serverConfig.GetRegion()); s3Error != ErrNone {
|
||||
errorIf(errSignatureMismatch, dumpRequest(r))
|
||||
writeErrorResponse(w, r, s3Error, r.URL.Path)
|
||||
return
|
||||
@ -197,7 +197,8 @@ func (api objectAPIHandlers) ListBucketsHandler(w http.ResponseWriter, r *http.R
|
||||
}
|
||||
|
||||
// List buckets does not support bucket policies, no need to enforce it.
|
||||
if s3Error := checkAuth(r); s3Error != ErrNone {
|
||||
// Proceed to validate signature.
|
||||
if s3Error := checkAuthWithRegion(r, ""); s3Error != ErrNone {
|
||||
errorIf(errSignatureMismatch, dumpRequest(r))
|
||||
writeErrorResponse(w, r, s3Error, r.URL.Path)
|
||||
return
|
||||
@ -243,7 +244,7 @@ func (api objectAPIHandlers) DeleteMultipleObjectsHandler(w http.ResponseWriter,
|
||||
return
|
||||
}
|
||||
case authTypePresigned, authTypeSigned:
|
||||
if s3Error := isReqAuthenticated(r); s3Error != ErrNone {
|
||||
if s3Error := isReqAuthenticated(r, serverConfig.GetRegion()); s3Error != ErrNone {
|
||||
errorIf(errSignatureMismatch, dumpRequest(r))
|
||||
writeErrorResponse(w, r, s3Error, r.URL.Path)
|
||||
return
|
||||
@ -357,7 +358,7 @@ func (api objectAPIHandlers) PutBucketHandler(w http.ResponseWriter, r *http.Req
|
||||
}
|
||||
|
||||
// PutBucket does not support policies, use checkAuth to validate signature.
|
||||
if s3Error := checkAuth(r); s3Error != ErrNone {
|
||||
if s3Error := checkAuthWithRegion(r, "us-east-1"); s3Error != ErrNone {
|
||||
errorIf(errSignatureMismatch, dumpRequest(r))
|
||||
writeErrorResponse(w, r, s3Error, r.URL.Path)
|
||||
return
|
||||
@ -490,7 +491,7 @@ func (api objectAPIHandlers) HeadBucketHandler(w http.ResponseWriter, r *http.Re
|
||||
return
|
||||
}
|
||||
case authTypePresigned, authTypeSigned:
|
||||
if s3Error := isReqAuthenticated(r); s3Error != ErrNone {
|
||||
if s3Error := isReqAuthenticated(r, serverConfig.GetRegion()); s3Error != ErrNone {
|
||||
errorIf(errSignatureMismatch, dumpRequest(r))
|
||||
writeErrorResponse(w, r, s3Error, r.URL.Path)
|
||||
return
|
||||
|
@ -140,7 +140,7 @@ func (api objectAPIHandlers) PutBucketPolicyHandler(w http.ResponseWriter, r *ht
|
||||
writeErrorResponse(w, r, ErrAccessDenied, r.URL.Path)
|
||||
return
|
||||
case authTypePresigned, authTypeSigned:
|
||||
if s3Error := isReqAuthenticated(r); s3Error != ErrNone {
|
||||
if s3Error := isReqAuthenticated(r, serverConfig.GetRegion()); s3Error != ErrNone {
|
||||
writeErrorResponse(w, r, s3Error, r.URL.Path)
|
||||
return
|
||||
}
|
||||
@ -223,7 +223,7 @@ func (api objectAPIHandlers) DeleteBucketPolicyHandler(w http.ResponseWriter, r
|
||||
writeErrorResponse(w, r, ErrAccessDenied, r.URL.Path)
|
||||
return
|
||||
case authTypePresigned, authTypeSigned:
|
||||
if s3Error := isReqAuthenticated(r); s3Error != ErrNone {
|
||||
if s3Error := isReqAuthenticated(r, serverConfig.GetRegion()); s3Error != ErrNone {
|
||||
writeErrorResponse(w, r, s3Error, r.URL.Path)
|
||||
return
|
||||
}
|
||||
@ -269,7 +269,7 @@ func (api objectAPIHandlers) GetBucketPolicyHandler(w http.ResponseWriter, r *ht
|
||||
writeErrorResponse(w, r, ErrAccessDenied, r.URL.Path)
|
||||
return
|
||||
case authTypePresigned, authTypeSigned:
|
||||
if s3Error := isReqAuthenticated(r); s3Error != ErrNone {
|
||||
if s3Error := isReqAuthenticated(r, serverConfig.GetRegion()); s3Error != ErrNone {
|
||||
writeErrorResponse(w, r, s3Error, r.URL.Path)
|
||||
return
|
||||
}
|
||||
|
@ -33,34 +33,28 @@ func isValidLocationConstraint(r *http.Request) (s3Error APIErrorCode) {
|
||||
// If the request has no body with content-length set to 0,
|
||||
// we do not have to validate location constraint. Bucket will
|
||||
// be created at default region.
|
||||
if r.ContentLength == 0 {
|
||||
return ErrNone
|
||||
}
|
||||
locationConstraint := createBucketLocationConfiguration{}
|
||||
if err := xmlDecoder(r.Body, &locationConstraint, r.ContentLength); err != nil {
|
||||
if err == io.EOF && r.ContentLength == -1 {
|
||||
// EOF is a valid condition here when ContentLength is -1.
|
||||
return ErrNone
|
||||
err := xmlDecoder(r.Body, &locationConstraint, r.ContentLength)
|
||||
if err == nil || err == io.EOF {
|
||||
// Successfully decoded, proceed to verify the region.
|
||||
// Once region has been obtained we proceed to verify it.
|
||||
incomingRegion := locationConstraint.Location
|
||||
if incomingRegion == "" {
|
||||
// Location constraint is empty for region "us-east-1",
|
||||
// in accordance with protocol.
|
||||
incomingRegion = "us-east-1"
|
||||
}
|
||||
errorIf(err, "Unable to xml decode location constraint")
|
||||
// Treat all other failures as XML parsing errors.
|
||||
return ErrMalformedXML
|
||||
} // Successfully decoded, proceed to verify the region.
|
||||
|
||||
// Once region has been obtained we proceed to verify it.
|
||||
incomingRegion := locationConstraint.Location
|
||||
if incomingRegion == "" {
|
||||
// Location constraint is empty for region "us-east-1",
|
||||
// in accordance with protocol.
|
||||
incomingRegion = "us-east-1"
|
||||
// Return errInvalidRegion if location constraint does not match
|
||||
// with configured region.
|
||||
s3Error = ErrNone
|
||||
if serverRegion != incomingRegion {
|
||||
s3Error = ErrInvalidRegion
|
||||
}
|
||||
return s3Error
|
||||
}
|
||||
// Return errInvalidRegion if location constraint does not match
|
||||
// with configured region.
|
||||
s3Error = ErrNone
|
||||
if serverRegion != incomingRegion {
|
||||
s3Error = ErrInvalidRegion
|
||||
}
|
||||
return s3Error
|
||||
errorIf(err, "Unable to xml decode location constraint")
|
||||
// Treat all other failures as XML parsing errors.
|
||||
return ErrMalformedXML
|
||||
}
|
||||
|
||||
// Supported headers that needs to be extracted.
|
||||
|
@ -111,7 +111,7 @@ func (api objectAPIHandlers) GetObjectHandler(w http.ResponseWriter, r *http.Req
|
||||
return
|
||||
}
|
||||
case authTypePresigned, authTypeSigned:
|
||||
if s3Error := isReqAuthenticated(r); s3Error != ErrNone {
|
||||
if s3Error := isReqAuthenticated(r, serverConfig.GetRegion()); s3Error != ErrNone {
|
||||
errorIf(errSignatureMismatch, dumpRequest(r))
|
||||
writeErrorResponse(w, r, s3Error, r.URL.Path)
|
||||
return
|
||||
@ -223,7 +223,7 @@ func (api objectAPIHandlers) HeadObjectHandler(w http.ResponseWriter, r *http.Re
|
||||
return
|
||||
}
|
||||
case authTypePresigned, authTypeSigned:
|
||||
if s3Error := isReqAuthenticated(r); s3Error != ErrNone {
|
||||
if s3Error := isReqAuthenticated(r, serverConfig.GetRegion()); s3Error != ErrNone {
|
||||
errorIf(errSignatureMismatch, dumpRequest(r))
|
||||
writeErrorResponse(w, r, s3Error, r.URL.Path)
|
||||
return
|
||||
@ -280,7 +280,7 @@ func (api objectAPIHandlers) CopyObjectHandler(w http.ResponseWriter, r *http.Re
|
||||
return
|
||||
}
|
||||
case authTypePresigned, authTypeSigned:
|
||||
if s3Error := isReqAuthenticated(r); s3Error != ErrNone {
|
||||
if s3Error := isReqAuthenticated(r, serverConfig.GetRegion()); s3Error != ErrNone {
|
||||
errorIf(errSignatureMismatch, dumpRequest(r))
|
||||
writeErrorResponse(w, r, s3Error, r.URL.Path)
|
||||
return
|
||||
@ -518,7 +518,7 @@ func (api objectAPIHandlers) NewMultipartUploadHandler(w http.ResponseWriter, r
|
||||
return
|
||||
}
|
||||
case authTypePresigned, authTypeSigned:
|
||||
if s3Error := isReqAuthenticated(r); s3Error != ErrNone {
|
||||
if s3Error := isReqAuthenticated(r, serverConfig.GetRegion()); s3Error != ErrNone {
|
||||
errorIf(errSignatureMismatch, dumpRequest(r))
|
||||
writeErrorResponse(w, r, s3Error, r.URL.Path)
|
||||
return
|
||||
@ -667,7 +667,7 @@ func (api objectAPIHandlers) AbortMultipartUploadHandler(w http.ResponseWriter,
|
||||
return
|
||||
}
|
||||
case authTypePresigned, authTypeSigned:
|
||||
if s3Error := isReqAuthenticated(r); s3Error != ErrNone {
|
||||
if s3Error := isReqAuthenticated(r, serverConfig.GetRegion()); s3Error != ErrNone {
|
||||
errorIf(errSignatureMismatch, dumpRequest(r))
|
||||
writeErrorResponse(w, r, s3Error, r.URL.Path)
|
||||
return
|
||||
@ -707,7 +707,7 @@ func (api objectAPIHandlers) ListObjectPartsHandler(w http.ResponseWriter, r *ht
|
||||
return
|
||||
}
|
||||
case authTypePresigned, authTypeSigned:
|
||||
if s3Error := isReqAuthenticated(r); s3Error != ErrNone {
|
||||
if s3Error := isReqAuthenticated(r, serverConfig.GetRegion()); s3Error != ErrNone {
|
||||
errorIf(errSignatureMismatch, dumpRequest(r))
|
||||
writeErrorResponse(w, r, s3Error, r.URL.Path)
|
||||
return
|
||||
@ -765,7 +765,7 @@ func (api objectAPIHandlers) CompleteMultipartUploadHandler(w http.ResponseWrite
|
||||
return
|
||||
}
|
||||
case authTypePresigned, authTypeSigned:
|
||||
if s3Error := isReqAuthenticated(r); s3Error != ErrNone {
|
||||
if s3Error := isReqAuthenticated(r, serverConfig.GetRegion()); s3Error != ErrNone {
|
||||
errorIf(errSignatureMismatch, dumpRequest(r))
|
||||
writeErrorResponse(w, r, s3Error, r.URL.Path)
|
||||
return
|
||||
@ -874,7 +874,7 @@ func (api objectAPIHandlers) DeleteObjectHandler(w http.ResponseWriter, r *http.
|
||||
return
|
||||
}
|
||||
case authTypeSigned, authTypePresigned:
|
||||
if s3Error := isReqAuthenticated(r); s3Error != ErrNone {
|
||||
if s3Error := isReqAuthenticated(r, serverConfig.GetRegion()); s3Error != ErrNone {
|
||||
errorIf(errSignatureMismatch, dumpRequest(r))
|
||||
writeErrorResponse(w, r, s3Error, r.URL.Path)
|
||||
return
|
||||
|
@ -194,13 +194,10 @@ func doesPolicySignatureMatch(formValues map[string]string) APIErrorCode {
|
||||
// doesPresignedSignatureMatch - Verify query headers with presigned signature
|
||||
// - http://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-query-string-auth.html
|
||||
// returns true if matches, false otherwise. if error is not nil then it is always false
|
||||
func doesPresignedSignatureMatch(hashedPayload string, r *http.Request, validateRegion bool) APIErrorCode {
|
||||
func doesPresignedSignatureMatch(hashedPayload string, r *http.Request, region string) APIErrorCode {
|
||||
// Access credentials.
|
||||
cred := serverConfig.GetCredential()
|
||||
|
||||
// Server region.
|
||||
region := serverConfig.GetRegion()
|
||||
|
||||
// Copy request
|
||||
req := *r
|
||||
|
||||
@ -223,15 +220,13 @@ func doesPresignedSignatureMatch(hashedPayload string, r *http.Request, validate
|
||||
|
||||
// Verify if region is valid.
|
||||
sRegion := pSignValues.Credential.scope.region
|
||||
// Should validate region, only if region is set. Some operations
|
||||
// do not need region validated for example GetBucketLocation.
|
||||
if validateRegion {
|
||||
if !isValidRegion(sRegion, region) {
|
||||
return ErrInvalidRegion
|
||||
}
|
||||
} else {
|
||||
// Should validate region, only if region is set.
|
||||
if region == "" {
|
||||
region = sRegion
|
||||
}
|
||||
if !isValidRegion(sRegion, region) {
|
||||
return ErrInvalidRegion
|
||||
}
|
||||
|
||||
// Extract all the signed headers along with its values.
|
||||
extractedSignedHeaders, errCode := extractSignedHeaders(pSignValues.SignedHeaders, req.Header)
|
||||
@ -322,13 +317,10 @@ func doesPresignedSignatureMatch(hashedPayload string, r *http.Request, validate
|
||||
// doesSignatureMatch - Verify authorization header with calculated header in accordance with
|
||||
// - http://docs.aws.amazon.com/AmazonS3/latest/API/sig-v4-authenticating-requests.html
|
||||
// returns true if matches, false otherwise. if error is not nil then it is always false
|
||||
func doesSignatureMatch(hashedPayload string, r *http.Request, validateRegion bool) APIErrorCode {
|
||||
func doesSignatureMatch(hashedPayload string, r *http.Request, region string) APIErrorCode {
|
||||
// Access credentials.
|
||||
cred := serverConfig.GetCredential()
|
||||
|
||||
// Server region.
|
||||
region := serverConfig.GetRegion()
|
||||
|
||||
// Copy request.
|
||||
req := *r
|
||||
|
||||
@ -372,14 +364,17 @@ func doesSignatureMatch(hashedPayload string, r *http.Request, validateRegion bo
|
||||
|
||||
// Verify if region is valid.
|
||||
sRegion := signV4Values.Credential.scope.region
|
||||
// Should validate region, only if region is set. Some operations
|
||||
// do not need region validated for example GetBucketLocation.
|
||||
if validateRegion {
|
||||
if !isValidRegion(sRegion, region) {
|
||||
return ErrInvalidRegion
|
||||
}
|
||||
// Region is set to be empty, we use whatever was sent by the
|
||||
// request and proceed further. This is a work-around to address
|
||||
// an important problem for ListBuckets() getting signed with
|
||||
// different regions.
|
||||
if region == "" {
|
||||
region = sRegion
|
||||
}
|
||||
// Should validate region, only if region is set.
|
||||
if !isValidRegion(sRegion, region) {
|
||||
return ErrInvalidRegion
|
||||
}
|
||||
region = sRegion
|
||||
|
||||
// Extract date, if not present throw error.
|
||||
var date string
|
||||
|
@ -106,15 +106,15 @@ func TestDoesPresignedSignatureMatch(t *testing.T) {
|
||||
credentialTemplate := "%s/%s/%s/s3/aws4_request"
|
||||
|
||||
testCases := []struct {
|
||||
queryParams map[string]string
|
||||
headers map[string]string
|
||||
verifyRegion bool
|
||||
expected APIErrorCode
|
||||
queryParams map[string]string
|
||||
headers map[string]string
|
||||
region string
|
||||
expected APIErrorCode
|
||||
}{
|
||||
// (0) Should error without a set URL query.
|
||||
{
|
||||
verifyRegion: false,
|
||||
expected: ErrInvalidQueryParams,
|
||||
region: "us-east-1",
|
||||
expected: ErrInvalidQueryParams,
|
||||
},
|
||||
// (1) Should error on an invalid access key.
|
||||
{
|
||||
@ -126,8 +126,8 @@ func TestDoesPresignedSignatureMatch(t *testing.T) {
|
||||
"X-Amz-SignedHeaders": "host;x-amz-content-sha256;x-amz-date",
|
||||
"X-Amz-Credential": fmt.Sprintf(credentialTemplate, "Z7IXGOO6BZ0REAN1Q26I", now.Format(yyyymmdd), "us-west-1"),
|
||||
},
|
||||
verifyRegion: false,
|
||||
expected: ErrInvalidAccessKeyID,
|
||||
region: "us-west-1",
|
||||
expected: ErrInvalidAccessKeyID,
|
||||
},
|
||||
// (2) Should error when the payload sha256 doesn't match.
|
||||
{
|
||||
@ -140,8 +140,8 @@ func TestDoesPresignedSignatureMatch(t *testing.T) {
|
||||
"X-Amz-Credential": fmt.Sprintf(credentialTemplate, serverConfig.GetCredential().AccessKeyID, now.Format(yyyymmdd), "us-west-1"),
|
||||
"X-Amz-Content-Sha256": "ThisIsNotThePayloadHash",
|
||||
},
|
||||
verifyRegion: false,
|
||||
expected: ErrContentSHA256Mismatch,
|
||||
region: "us-west-1",
|
||||
expected: ErrContentSHA256Mismatch,
|
||||
},
|
||||
// (3) Should fail with an invalid region.
|
||||
{
|
||||
@ -154,8 +154,8 @@ func TestDoesPresignedSignatureMatch(t *testing.T) {
|
||||
"X-Amz-Credential": fmt.Sprintf(credentialTemplate, serverConfig.GetCredential().AccessKeyID, now.Format(yyyymmdd), "us-west-1"),
|
||||
"X-Amz-Content-Sha256": payload,
|
||||
},
|
||||
verifyRegion: true,
|
||||
expected: ErrInvalidRegion,
|
||||
region: "us-east-1",
|
||||
expected: ErrInvalidRegion,
|
||||
},
|
||||
// (4) Should NOT fail with an invalid region if it doesn't verify it.
|
||||
{
|
||||
@ -168,8 +168,8 @@ func TestDoesPresignedSignatureMatch(t *testing.T) {
|
||||
"X-Amz-Credential": fmt.Sprintf(credentialTemplate, serverConfig.GetCredential().AccessKeyID, now.Format(yyyymmdd), "us-west-1"),
|
||||
"X-Amz-Content-Sha256": payload,
|
||||
},
|
||||
verifyRegion: false,
|
||||
expected: ErrUnsignedHeaders,
|
||||
region: "us-west-1",
|
||||
expected: ErrUnsignedHeaders,
|
||||
},
|
||||
// (5) Should fail to extract headers if the host header is not signed.
|
||||
{
|
||||
@ -182,8 +182,8 @@ func TestDoesPresignedSignatureMatch(t *testing.T) {
|
||||
"X-Amz-Credential": fmt.Sprintf(credentialTemplate, serverConfig.GetCredential().AccessKeyID, now.Format(yyyymmdd), serverConfig.GetRegion()),
|
||||
"X-Amz-Content-Sha256": payload,
|
||||
},
|
||||
verifyRegion: true,
|
||||
expected: ErrUnsignedHeaders,
|
||||
region: serverConfig.GetRegion(),
|
||||
expected: ErrUnsignedHeaders,
|
||||
},
|
||||
// (6) Should give an expired request if it has expired.
|
||||
{
|
||||
@ -200,8 +200,8 @@ func TestDoesPresignedSignatureMatch(t *testing.T) {
|
||||
"X-Amz-Date": now.AddDate(0, 0, -2).Format(iso8601Format),
|
||||
"X-Amz-Content-Sha256": payload,
|
||||
},
|
||||
verifyRegion: false,
|
||||
expected: ErrExpiredPresignRequest,
|
||||
region: serverConfig.GetRegion(),
|
||||
expected: ErrExpiredPresignRequest,
|
||||
},
|
||||
// (7) Should error if the signature is incorrect.
|
||||
{
|
||||
@ -218,8 +218,8 @@ func TestDoesPresignedSignatureMatch(t *testing.T) {
|
||||
"X-Amz-Date": now.Format(iso8601Format),
|
||||
"X-Amz-Content-Sha256": payload,
|
||||
},
|
||||
verifyRegion: false,
|
||||
expected: ErrSignatureDoesNotMatch,
|
||||
region: serverConfig.GetRegion(),
|
||||
expected: ErrSignatureDoesNotMatch,
|
||||
},
|
||||
}
|
||||
|
||||
@ -243,7 +243,7 @@ func TestDoesPresignedSignatureMatch(t *testing.T) {
|
||||
}
|
||||
|
||||
// Check if it matches!
|
||||
err := doesPresignedSignatureMatch(payload, req, testCase.verifyRegion)
|
||||
err := doesPresignedSignatureMatch(payload, req, testCase.region)
|
||||
if err != testCase.expected {
|
||||
t.Errorf("(%d) expected to get %s, instead got %s", i, niceError(testCase.expected), niceError(err))
|
||||
}
|
||||
|
@ -19,10 +19,11 @@ package cmd
|
||||
import (
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"github.com/minio/sha256-simd"
|
||||
"hash"
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
"github.com/minio/sha256-simd"
|
||||
)
|
||||
|
||||
// signVerifyReader represents an io.Reader compatible interface which
|
||||
@ -49,7 +50,7 @@ func isSignVerify(reader io.Reader) bool {
|
||||
|
||||
// Verify - verifies signature and returns error upon signature mismatch.
|
||||
func (v *signVerifyReader) Verify() error {
|
||||
validateRegion := true // Defaults to validating region.
|
||||
region := serverConfig.GetRegion()
|
||||
shaPayloadHex := hex.EncodeToString(v.HashWriter.Sum(nil))
|
||||
if skipContentSha256Cksum(v.Request) {
|
||||
// Sets 'UNSIGNED-PAYLOAD' if client requested to not calculated sha256.
|
||||
@ -58,9 +59,9 @@ func (v *signVerifyReader) Verify() error {
|
||||
// Signature verification block.
|
||||
var s3Error APIErrorCode
|
||||
if isRequestSignatureV4(v.Request) {
|
||||
s3Error = doesSignatureMatch(shaPayloadHex, v.Request, validateRegion)
|
||||
s3Error = doesSignatureMatch(shaPayloadHex, v.Request, region)
|
||||
} else if isRequestPresignedSignatureV4(v.Request) {
|
||||
s3Error = doesPresignedSignatureMatch(shaPayloadHex, v.Request, validateRegion)
|
||||
s3Error = doesPresignedSignatureMatch(shaPayloadHex, v.Request, region)
|
||||
} else {
|
||||
// Couldn't figure out the request type, set the error as AccessDenied.
|
||||
s3Error = ErrAccessDenied
|
||||
|
Loading…
Reference in New Issue
Block a user