signature: No need to validate region for getBucketLocation and listBuckets.

This type of check is added for making sure that we can support
custom regions.

ListBuckets and GetBucketLocation are always "us-east-1" rest
should look for the configured region.

Fixes #1278
master
Harshavardhana 9 years ago
parent 2c793a2ea7
commit a6a4e7e297
  1. 5
      auth-handler.go
  2. 50
      bucket-handlers.go
  3. 12
      object-handlers.go
  4. 21
      signature-v4.go

@ -129,10 +129,11 @@ func isReqAuthenticated(r *http.Request) (s3Error APIErrorCode) {
} }
// Populate back the payload. // Populate back the payload.
r.Body = ioutil.NopCloser(bytes.NewReader(payload)) r.Body = ioutil.NopCloser(bytes.NewReader(payload))
validateRegion := true // Validate region.
if isRequestSignatureV4(r) { if isRequestSignatureV4(r) {
return doesSignatureMatch(hex.EncodeToString(sum256(payload)), r) return doesSignatureMatch(hex.EncodeToString(sum256(payload)), r, validateRegion)
} else if isRequestPresignedSignatureV4(r) { } else if isRequestPresignedSignatureV4(r) {
return doesPresignedSignatureMatch(r) return doesPresignedSignatureMatch(r, validateRegion)
} }
return ErrAccessDenied return ErrAccessDenied
} }

@ -18,6 +18,8 @@ package main
import ( import (
"bytes" "bytes"
"encoding/base64"
"encoding/hex"
"encoding/xml" "encoding/xml"
"io" "io"
"io/ioutil" "io/ioutil"
@ -88,7 +90,28 @@ func (api objectStorageAPI) GetBucketLocationHandler(w http.ResponseWriter, r *h
return return
} }
case authTypeSigned, authTypePresigned: case authTypeSigned, authTypePresigned:
if s3Error := isReqAuthenticated(r); s3Error != ErrNone { payload, e := ioutil.ReadAll(r.Body)
if e != nil {
writeErrorResponse(w, r, ErrInternalError, r.URL.Path)
return
}
// Verify Content-Md5, if payload is set.
if r.Header.Get("Content-Md5") != "" {
if r.Header.Get("Content-Md5") != base64.StdEncoding.EncodeToString(sumMD5(payload)) {
writeErrorResponse(w, r, ErrBadDigest, r.URL.Path)
return
}
}
// Populate back the payload.
r.Body = ioutil.NopCloser(bytes.NewReader(payload))
var s3Error APIErrorCode // API error code.
validateRegion := false // Validate region.
if isRequestSignatureV4(r) {
s3Error = doesSignatureMatch(hex.EncodeToString(sum256(payload)), r, validateRegion)
} else if isRequestPresignedSignatureV4(r) {
s3Error = doesPresignedSignatureMatch(r, validateRegion)
}
if s3Error != ErrNone {
writeErrorResponse(w, r, s3Error, r.URL.Path) writeErrorResponse(w, r, s3Error, r.URL.Path)
return return
} }
@ -117,7 +140,7 @@ func (api objectStorageAPI) GetBucketLocationHandler(w http.ResponseWriter, r *h
Location: region, Location: region,
}) })
} }
setCommonHeaders(w) // write headers. setCommonHeaders(w) // Write headers.
writeSuccessResponse(w, encodedSuccessResponse) writeSuccessResponse(w, encodedSuccessResponse)
} }
@ -256,7 +279,28 @@ func (api objectStorageAPI) ListBucketsHandler(w http.ResponseWriter, r *http.Re
writeErrorResponse(w, r, ErrAccessDenied, r.URL.Path) writeErrorResponse(w, r, ErrAccessDenied, r.URL.Path)
return return
case authTypeSigned, authTypePresigned: case authTypeSigned, authTypePresigned:
if s3Error := isReqAuthenticated(r); s3Error != ErrNone { payload, e := ioutil.ReadAll(r.Body)
if e != nil {
writeErrorResponse(w, r, ErrInternalError, r.URL.Path)
return
}
// Verify Content-Md5, if payload is set.
if r.Header.Get("Content-Md5") != "" {
if r.Header.Get("Content-Md5") != base64.StdEncoding.EncodeToString(sumMD5(payload)) {
writeErrorResponse(w, r, ErrBadDigest, r.URL.Path)
return
}
}
// Populate back the payload.
r.Body = ioutil.NopCloser(bytes.NewReader(payload))
var s3Error APIErrorCode // API error code.
validateRegion := false // Validate region.
if isRequestSignatureV4(r) {
s3Error = doesSignatureMatch(hex.EncodeToString(sum256(payload)), r, validateRegion)
} else if isRequestPresignedSignatureV4(r) {
s3Error = doesPresignedSignatureMatch(r, validateRegion)
}
if s3Error != ErrNone {
writeErrorResponse(w, r, s3Error, r.URL.Path) writeErrorResponse(w, r, s3Error, r.URL.Path)
return return
} }

@ -601,8 +601,9 @@ func (api objectStorageAPI) PutObjectHandler(w http.ResponseWriter, r *http.Requ
// Create anonymous object. // Create anonymous object.
objectInfo, err = api.ObjectAPI.PutObject(bucket, object, size, r.Body, nil) objectInfo, err = api.ObjectAPI.PutObject(bucket, object, size, r.Body, nil)
case authTypePresigned: case authTypePresigned:
validateRegion := true // Validate region.
// For presigned requests verify them right here. // For presigned requests verify them right here.
if apiErr := doesPresignedSignatureMatch(r); apiErr != ErrNone { if apiErr := doesPresignedSignatureMatch(r, validateRegion); apiErr != ErrNone {
writeErrorResponse(w, r, apiErr, r.URL.Path) writeErrorResponse(w, r, apiErr, r.URL.Path)
return return
} }
@ -622,7 +623,8 @@ func (api objectStorageAPI) PutObjectHandler(w http.ResponseWriter, r *http.Requ
return return
} }
shaPayload := shaWriter.Sum(nil) shaPayload := shaWriter.Sum(nil)
if apiErr := doesSignatureMatch(hex.EncodeToString(shaPayload), r); apiErr != ErrNone { validateRegion := true // Validate region.
if apiErr := doesSignatureMatch(hex.EncodeToString(shaPayload), r, validateRegion); apiErr != ErrNone {
if apiErr == ErrSignatureDoesNotMatch { if apiErr == ErrSignatureDoesNotMatch {
writer.CloseWithError(errSignatureMismatch) writer.CloseWithError(errSignatureMismatch)
return return
@ -779,8 +781,9 @@ func (api objectStorageAPI) PutObjectPartHandler(w http.ResponseWriter, r *http.
// already allowed. // already allowed.
partMD5, err = api.ObjectAPI.PutObjectPart(bucket, object, uploadID, partID, size, r.Body, hex.EncodeToString(md5Bytes)) partMD5, err = api.ObjectAPI.PutObjectPart(bucket, object, uploadID, partID, size, r.Body, hex.EncodeToString(md5Bytes))
case authTypePresigned: case authTypePresigned:
validateRegion := true // Validate region.
// For presigned requests verify right here. // For presigned requests verify right here.
apiErr := doesPresignedSignatureMatch(r) apiErr := doesPresignedSignatureMatch(r, validateRegion)
if apiErr != ErrNone { if apiErr != ErrNone {
writeErrorResponse(w, r, apiErr, r.URL.Path) writeErrorResponse(w, r, apiErr, r.URL.Path)
return return
@ -800,7 +803,8 @@ func (api objectStorageAPI) PutObjectPartHandler(w http.ResponseWriter, r *http.
return return
} }
shaPayload := shaWriter.Sum(nil) shaPayload := shaWriter.Sum(nil)
if apiErr := doesSignatureMatch(hex.EncodeToString(shaPayload), r); apiErr != ErrNone { validateRegion := true // Validate region.
if apiErr := doesSignatureMatch(hex.EncodeToString(shaPayload), r, validateRegion); apiErr != ErrNone {
if apiErr == ErrSignatureDoesNotMatch { if apiErr == ErrSignatureDoesNotMatch {
writer.CloseWithError(errSignatureMismatch) writer.CloseWithError(errSignatureMismatch)
return return

@ -195,7 +195,8 @@ func doesPolicySignatureMatch(formValues map[string]string) APIErrorCode {
} }
// Verify if the region is valid. // Verify if the region is valid.
if !isValidRegion(credHeader.scope.region, region) { sRegion := credHeader.scope.region
if !isValidRegion(sRegion, region) {
return ErrInvalidRegion return ErrInvalidRegion
} }
@ -221,7 +222,7 @@ func doesPolicySignatureMatch(formValues map[string]string) APIErrorCode {
// doesPresignedSignatureMatch - Verify query headers with presigned signature // doesPresignedSignatureMatch - Verify query headers with presigned signature
// - http://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-query-string-auth.html // - 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 // returns true if matches, false otherwise. if error is not nil then it is always false
func doesPresignedSignatureMatch(r *http.Request) APIErrorCode { func doesPresignedSignatureMatch(r *http.Request, validateRegion bool) APIErrorCode {
// Access credentials. // Access credentials.
cred := serverConfig.GetCredential() cred := serverConfig.GetCredential()
@ -244,9 +245,15 @@ func doesPresignedSignatureMatch(r *http.Request) APIErrorCode {
// Verify if region is valid. // Verify if region is valid.
sRegion := preSignValues.Credential.scope.region sRegion := preSignValues.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) { if !isValidRegion(sRegion, region) {
return ErrInvalidRegion return ErrInvalidRegion
} }
} else {
region = sRegion
}
// Extract all the signed headers along with its values. // Extract all the signed headers along with its values.
extractedSignedHeaders := extractSignedHeaders(preSignValues.SignedHeaders, req.Header) extractedSignedHeaders := extractSignedHeaders(preSignValues.SignedHeaders, req.Header)
@ -267,7 +274,7 @@ func doesPresignedSignatureMatch(r *http.Request) APIErrorCode {
query.Set("X-Amz-Date", t.Format(iso8601Format)) query.Set("X-Amz-Date", t.Format(iso8601Format))
query.Set("X-Amz-Expires", strconv.Itoa(expireSeconds)) query.Set("X-Amz-Expires", strconv.Itoa(expireSeconds))
query.Set("X-Amz-SignedHeaders", getSignedHeaders(extractedSignedHeaders)) query.Set("X-Amz-SignedHeaders", getSignedHeaders(extractedSignedHeaders))
query.Set("X-Amz-Credential", cred.AccessKeyID+"/"+getScope(t, region)) query.Set("X-Amz-Credential", cred.AccessKeyID+"/"+getScope(t, sRegion))
// Save other headers available in the request parameters. // Save other headers available in the request parameters.
for k, v := range req.URL.Query() { for k, v := range req.URL.Query() {
@ -321,7 +328,7 @@ func doesPresignedSignatureMatch(r *http.Request) APIErrorCode {
// doesSignatureMatch - Verify authorization header with calculated header in accordance with // doesSignatureMatch - Verify authorization header with calculated header in accordance with
// - http://docs.aws.amazon.com/AmazonS3/latest/API/sig-v4-authenticating-requests.html // - 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 // returns true if matches, false otherwise. if error is not nil then it is always false
func doesSignatureMatch(hashedPayload string, r *http.Request) APIErrorCode { func doesSignatureMatch(hashedPayload string, r *http.Request, validateRegion bool) APIErrorCode {
// Access credentials. // Access credentials.
cred := serverConfig.GetCredential() cred := serverConfig.GetCredential()
@ -350,9 +357,15 @@ func doesSignatureMatch(hashedPayload string, r *http.Request) APIErrorCode {
// Verify if region is valid. // Verify if region is valid.
sRegion := signV4Values.Credential.scope.region 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) { if !isValidRegion(sRegion, region) {
return ErrInvalidRegion return ErrInvalidRegion
} }
} else {
region = sRegion
}
// Extract date, if not present throw error. // Extract date, if not present throw error.
var date string var date string

Loading…
Cancel
Save