signv2: Do not use path encoding for query values. (#3458)

Use query unescape before comparing signature.
This commit is contained in:
Harshavardhana 2016-12-15 14:56:18 -08:00 committed by GitHub
parent 5c481fbf6e
commit 0db484c8f6
2 changed files with 23 additions and 4 deletions

View File

@ -22,6 +22,7 @@ import (
"encoding/base64" "encoding/base64"
"fmt" "fmt"
"net/http" "net/http"
"net/url"
"sort" "sort"
"strconv" "strconv"
"strings" "strings"
@ -99,20 +100,27 @@ func doesPresignV2SignatureMatch(r *http.Request) APIErrorCode {
var gotSignature string var gotSignature string
var expires string var expires string
var accessKey string var accessKey string
var err error
for _, query := range queries { for _, query := range queries {
keyval := strings.Split(query, "=") keyval := strings.Split(query, "=")
switch keyval[0] { switch keyval[0] {
case "AWSAccessKeyId": case "AWSAccessKeyId":
accessKey = keyval[1] accessKey, err = url.QueryUnescape(keyval[1])
case "Signature": case "Signature":
gotSignature = keyval[1] gotSignature, err = url.QueryUnescape(keyval[1])
case "Expires": case "Expires":
expires = keyval[1] expires, err = url.QueryUnescape(keyval[1])
default: default:
filteredQueries = append(filteredQueries, query) filteredQueries = append(filteredQueries, query)
} }
} }
// Check if the query unescaped properly.
if err != nil {
errorIf(err, "Unable to unescape query values", queries)
return ErrInvalidQueryParams
}
// Invalid access key.
if accessKey == "" { if accessKey == "" {
return ErrInvalidQueryParams return ErrInvalidQueryParams
} }
@ -128,12 +136,13 @@ func doesPresignV2SignatureMatch(r *http.Request) APIErrorCode {
return ErrMalformedExpires return ErrMalformedExpires
} }
// Check if the presigned URL has expired.
if expiresInt < time.Now().UTC().Unix() { if expiresInt < time.Now().UTC().Unix() {
return ErrExpiredPresignRequest return ErrExpiredPresignRequest
} }
expectedSignature := preSignatureV2(r.Method, encodedResource, strings.Join(filteredQueries, "&"), r.Header, expires) expectedSignature := preSignatureV2(r.Method, encodedResource, strings.Join(filteredQueries, "&"), r.Header, expires)
if gotSignature != getURLEncodedName(expectedSignature) { if gotSignature != expectedSignature {
return ErrSignatureDoesNotMatch return ErrSignatureDoesNotMatch
} }

View File

@ -22,6 +22,7 @@ func TestResourceListSorting(t *testing.T) {
} }
} }
// Tests presigned v2 signature.
func TestDoesPresignedV2SignatureMatch(t *testing.T) { func TestDoesPresignedV2SignatureMatch(t *testing.T) {
root, err := newTestConfig("us-east-1") root, err := newTestConfig("us-east-1")
if err != nil { if err != nil {
@ -76,6 +77,15 @@ func TestDoesPresignedV2SignatureMatch(t *testing.T) {
}, },
expected: ErrSignatureDoesNotMatch, expected: ErrSignatureDoesNotMatch,
}, },
// (5) Should error when the signature does not match.
{
queryParams: map[string]string{
"Expires": fmt.Sprintf("%d", now.Unix()),
"Signature": "zOM2YrY/yAQe15VWmT78OlBrK6g=",
"AWSAccessKeyId": serverConfig.GetCredential().AccessKeyID,
},
expected: ErrSignatureDoesNotMatch,
},
} }
// Run each test case individually. // Run each test case individually.