aws / aws-sdk-go-v2

AWS SDK for the Go programming language.
https://aws.github.io/aws-sdk-go-v2/docs/
Apache License 2.0
2.61k stars 627 forks source link

Presignedurl requestpayer change #2768

Closed bhavya2109sharma closed 1 month ago

bhavya2109sharma commented 1 month ago

The AWS Go SDK V2 does not currently sign the x-amz-request-payer header when generating presigned URLs. This requires clients to manually add the header, which can lead to SignatureDoesNotMatch errors.

This PR updates the signer implementation to include the x-amz-request-payer header in the signed URL, allowing clients to use the presigned URL without needing to add the header.

Fixes : https://github.com/aws/aws-sdk-go-v2/issues/2764

Testing:

PresignedURL before the change

https://demo-bucket.s3.us-east-1.amazonaws.com/key?
X-Amz-Credential=REDACTED/20240830/us-east-1/s3/aws4_request&
X-Amz-Date=20240830T170032Z&
X-Amz-Expires=900&
X-Amz-SignedHeaders=host;x-amz-request-payer&
x-id=GetObject&
X-Amz-Signature=REDACTED&
X-Amz-Algorithm=AWS4-HMAC-SHA256 

PresignedURL after the change

https://demo-bucket.s3.us-east-1.amazonaws.com/key?
X-Amz-Date=20240830T165708Z&
X-Amz-Expires=900&
X-Amz-Request-Payer=requester&
X-Amz-SignedHeaders=host&
x-id=GetObject&
X-Amz-Signature=REDACTED&
X-Amz-Algorithm=AWS4-HMAC-SHA256&
X-Amz-Credential=REDACTED/20240830/us-east-1/s3/aws4_request 
package main 

import (
    "context"
    "fmt"
    "github.com/aws/aws-sdk-go-v2/aws"
    "github.com/aws/aws-sdk-go-v2/config"
    "github.com/aws/aws-sdk-go-v2/service/s3"
    "github.com/aws/aws-sdk-go-v2/service/s3/types"
    "net/http"
    "net/url"
    "regexp"
    "strings"
)

func main() {

    cfg, err := config.LoadDefaultConfig(context.TODO(), config.WithRegion("us-east-1"),
        config.WithClientLogMode(aws.LogRequestWithBody|aws.LogResponseWithBody))

    if err != nil {
        panic(err)
    }
    client := s3.NewFromConfig(cfg)
    presigner := s3.NewPresignClient(client)

    presignedreq, err := presigner.PresignGetObject(context.TODO(), &s3.GetObjectInput{
        Bucket:       aws.String("demo-bucket"),
        Key:          aws.String("key"),
        RequestPayer: types.RequestPayerRequester,
    })

    if err != nil {
        panic(err)
    }
    req, err := http.NewRequest("GET", presignedreq.URL, nil)
    if err != nil {
        panic(err)
    }
    clientHTTP := &http.Client{}
    resp, err := clientHTTP.Do(req)
    if err != nil {
        panic(err)
    }
    defer resp.Body.Close()

    fmt.Println("HTTP Status:", resp.Status)
        //HTTP Status: 200 OK
}