Skip to content

Commit

Permalink
The authorization header was being calculated incorrectly due to inco…
Browse files Browse the repository at this point in the history
…rrect sorting on amz headers when there existed a header that started with an underscore. The http.Header implementation automatically camel cases headers. We were sorting the header keys before lower casing them when calculating the authorization header. Since underscore sorts differently when compared to upper and lower cased alpha characters, this created an incorrect sort order in the stringToSign. Fixed sorting to take place after lower casing header keys. Also fixed two stale tests that were failing due to unrelated issues. (#122)
  • Loading branch information
RachelTucker authored Feb 18, 2021
1 parent eb72495 commit 6f15864
Show file tree
Hide file tree
Showing 4 changed files with 31 additions and 17 deletions.
12 changes: 12 additions & 0 deletions ds3/networking/canonicalHeaders.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package networking

// Used to correctly sort headers when creating the stringToSign for the authorization header.
type CanonicalHeader struct{
key string // key is assumed to be lower cased
values []string
}
type CanonicalHeaders []CanonicalHeader

func (p CanonicalHeaders) Len() int { return len(p) }
func (p CanonicalHeaders) Less(i, j int) bool { return p[i].key < p[j].key }
func (p CanonicalHeaders) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
2 changes: 1 addition & 1 deletion ds3/networking/headers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import (
)

func TestBuildAuthHeaderValue(t *testing.T) {
expected := "AWS access:1JbBTxv5KRFKbvju7w27c2J6bKk="
expected := "AWS access:gmW4yg/tw02UYleIqGn5ebvKbr8="

fields := signatureFields{
Verb:"PUT",
Expand Down
24 changes: 11 additions & 13 deletions ds3/networking/httpRequestBuilder.go
Original file line number Diff line number Diff line change
Expand Up @@ -207,33 +207,31 @@ func (builder *HttpRequestBuilder) maybeAddSignatureQueryParams() {
}

func (builder *HttpRequestBuilder) maybeAddAmazonCanonicalHeaders() {
headerKeys := make([]string, 0)
var canonicalHeaders CanonicalHeaders

for key, value := range *builder.headers {
lowerCaseKey := strings.ToLower(key)
if strings.HasPrefix(lowerCaseKey, models.AMZ_META_HEADER) && len(value) > 0 {
headerKeys = append(headerKeys, key)
canonicalHeaders = append(canonicalHeaders, CanonicalHeader{
key: lowerCaseKey,
values: value,
})
}
}

if len(headerKeys) == 0 {
if len(canonicalHeaders) == 0 {
return
}

sort.Strings(headerKeys)
sort.Sort(canonicalHeaders)

var stringBuilder strings.Builder

var httpHeaders map[string][]string = *builder.headers

for _, headerKey := range headerKeys {
lowerCaseKey := strings.ToLower(headerKey)
headerValue := httpHeaders[headerKey]

if len(headerValue) > 0 {
stringBuilder.WriteString(lowerCaseKey)
for _, header := range canonicalHeaders {
if len(header.values) > 0 {
stringBuilder.WriteString(header.key)
stringBuilder.WriteString(":")
stringBuilder.WriteString(strings.Join(headerValue, ","))
stringBuilder.WriteString(strings.Join(header.values, ","))
stringBuilder.WriteString("\n")
}
}
Expand Down
10 changes: 7 additions & 3 deletions ds3_integration/smoke_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -176,8 +176,8 @@ func TestDeleteBucketNonEmpty(t *testing.T) {
putObjErr := testutils.PutObjectLogError(t, client, bucketName, beowulf, book)
ds3Testing.AssertNilError(t, putObjErr)

//Attempt to delete non-empty bucket
deleteErr := testutils.DeleteBucket(client, bucketName)
//Attempt to delete non-empty bucket without force
_, deleteErr := client.DeleteBucketSpectraS3(models.NewDeleteBucketSpectraS3Request(bucketName))
ds3Testing.AssertBadStatusCodeError(t, 409, deleteErr)
}

Expand Down Expand Up @@ -544,7 +544,11 @@ func TestPuttingZeroLengthObject(t *testing.T) {

zeroBytes := make([]byte, 0)

putObjectRequest := models.NewPutObjectRequest(bucketName, objectName, ds3.BuildByteReaderWithSizeDecorator(zeroBytes))
putObjectRequest := models.NewPutObjectRequest(bucketName, objectName, ds3.BuildByteReaderWithSizeDecorator(zeroBytes)).
WithMetaData("_c", "C").
WithMetaData("d", "D").
WithMetaData("_a", "A").
WithMetaData("b", "B")

_, err = client.PutObject(putObjectRequest)

Expand Down

0 comments on commit 6f15864

Please sign in to comment.