forked from TrueCloudLab/frostfs-s3-gw
[#339] v4: Don't duplicate content-length as signed header
Signed-off-by: Denis Kirillov <d.kirillov@yadro.com>
This commit is contained in:
parent
11c1a86404
commit
9395b5f39d
3 changed files with 54 additions and 10 deletions
|
@ -139,6 +139,45 @@ Testing with the {sdk-java}
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestSignatureV4(t *testing.T) {
|
||||||
|
signer := v4.NewSigner(func(options *v4.SignerOptions) {
|
||||||
|
options.DisableURIPathEscaping = true
|
||||||
|
options.Logger = zaptest.NewLogger(t)
|
||||||
|
options.LogSigning = true
|
||||||
|
})
|
||||||
|
|
||||||
|
creds := aws.Credentials{
|
||||||
|
AccessKeyID: "9CBEGH8T9XfLin2pg7LG8ZxBH1PnZc1yoioViKngrUnu0CbC2mcjpcw9t4Y7AS6zsF5cJGkDhXAx5hxFDKwfZzgj7",
|
||||||
|
SecretAccessKey: "8742218da7f905de24f633f44efe02f82c6d2a317ed6f99592627215d17816e3",
|
||||||
|
}
|
||||||
|
|
||||||
|
bodyStr := `tmp2
|
||||||
|
`
|
||||||
|
body := bytes.NewBufferString(bodyStr)
|
||||||
|
|
||||||
|
req, err := http.NewRequest("PUT", "http://localhost:8084/main/tmp2", body)
|
||||||
|
require.NoError(t, err)
|
||||||
|
req.Header.Set("Authorization", "AWS4-HMAC-SHA256 Credential=9CBEGH8T9XfLin2pg7LG8ZxBH1PnZc1yoioViKngrUnu0CbC2mcjpcw9t4Y7AS6zsF5cJGkDhXAx5hxFDKwfZzgj7/20241210/ru/s3/aws4_request, SignedHeaders=content-md5;host;x-amz-content-sha256;x-amz-date, Signature=945664a5bccfd37a1167ca5e718e2b883f68a7ccf7f1044768e7fe58b737b7ed")
|
||||||
|
req.Header.Set("Content-Length", "5")
|
||||||
|
req.Header.Set("User-Agent", "aws-cli/2.13.2 Python/3.11.4 Linux/6.4.5-x64v1-xanmod1 exe/x86_64.debian.11 prompt/off command/s3api.put-object")
|
||||||
|
req.Header.Set("Content-MD5", "DstU4KxdzBj5jTGltfyqgA==")
|
||||||
|
req.Header.Set("Expect", "101-continue")
|
||||||
|
req.Header.Set("X-Amz-Content-Sha256", "1f9b7417ee5445c41dbe904c3651eb0ba1c12fecff16c1bccd8df3db6e390b5f")
|
||||||
|
req.Header.Set("X-Amz-Date", "20241210T114611Z")
|
||||||
|
|
||||||
|
service := "s3"
|
||||||
|
region := "ru"
|
||||||
|
signature := "945664a5bccfd37a1167ca5e718e2b883f68a7ccf7f1044768e7fe58b737b7ed"
|
||||||
|
signingTime, err := time.Parse("20060102T150405Z", "20241210T114611Z")
|
||||||
|
require.NoError(t, err)
|
||||||
|
cloned := cloneRequest(req, &AuthHeader{SignedFields: []string{"content-md5", "host", "x-amz-content-sha256", "x-amz-date"}})
|
||||||
|
|
||||||
|
err = signer.SignHTTP(cloned.Context(), creds, cloned, "1f9b7417ee5445c41dbe904c3651eb0ba1c12fecff16c1bccd8df3db6e390b5f", service, region, signingTime)
|
||||||
|
require.NoError(t, err)
|
||||||
|
signatureComputed := NewRegexpMatcher(AuthorizationFieldRegexp).GetSubmatches(cloned.Header.Get(AuthorizationHdr))["v4_signature"]
|
||||||
|
require.Equal(t, signature, signatureComputed, "signature mismatched")
|
||||||
|
}
|
||||||
|
|
||||||
func TestCheckFormatContentSHA256(t *testing.T) {
|
func TestCheckFormatContentSHA256(t *testing.T) {
|
||||||
defaultErr := errors.GetAPIError(errors.ErrContentSHA256Mismatch)
|
defaultErr := errors.GetAPIError(errors.ErrContentSHA256Mismatch)
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
// This is https://github.com/aws/aws-sdk-go-v2/blob/a2b751d1ba71f59175a41f9cae5f159f1044360f/aws/signer/v4/v4.go
|
// This is https://github.com/aws/aws-sdk-go-v2/blob/a2b751d1ba71f59175a41f9cae5f159f1044360f/aws/signer/v4/v4.go
|
||||||
// with changes:
|
// with changes:
|
||||||
// * using different headers for sign/presign
|
// * using different headers for sign/presign
|
||||||
|
// * don't duplicate content-length as signed header
|
||||||
// * use copy of smithy-go encoding/httpbinding package
|
// * use copy of smithy-go encoding/httpbinding package
|
||||||
// * use zap.Logger instead of smithy-go/logging
|
// * use zap.Logger instead of smithy-go/logging
|
||||||
|
|
||||||
|
@ -54,7 +55,6 @@ import (
|
||||||
"net/textproto"
|
"net/textproto"
|
||||||
"net/url"
|
"net/url"
|
||||||
"sort"
|
"sort"
|
||||||
"strconv"
|
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -440,20 +440,20 @@ func (s *httpSigner) buildCanonicalHeaders(host string, rule v4Internal.Rule, he
|
||||||
headers = append(headers, hostHeader)
|
headers = append(headers, hostHeader)
|
||||||
signed[hostHeader] = append(signed[hostHeader], host)
|
signed[hostHeader] = append(signed[hostHeader], host)
|
||||||
|
|
||||||
const contentLengthHeader = "content-length"
|
//const contentLengthHeader = "content-length"
|
||||||
if length > 0 {
|
//if length > 0 {
|
||||||
headers = append(headers, contentLengthHeader)
|
// headers = append(headers, contentLengthHeader)
|
||||||
signed[contentLengthHeader] = append(signed[contentLengthHeader], strconv.FormatInt(length, 10))
|
// signed[contentLengthHeader] = append(signed[contentLengthHeader], strconv.FormatInt(length, 10))
|
||||||
}
|
//}
|
||||||
|
|
||||||
for k, v := range header {
|
for k, v := range header {
|
||||||
if !rule.IsValid(k) {
|
if !rule.IsValid(k) {
|
||||||
continue // ignored header
|
continue // ignored header
|
||||||
}
|
}
|
||||||
if strings.EqualFold(k, contentLengthHeader) {
|
//if strings.EqualFold(k, contentLengthHeader) {
|
||||||
// prevent signing already handled content-length header.
|
// // prevent signing already handled content-length header.
|
||||||
continue
|
// continue
|
||||||
}
|
//}
|
||||||
|
|
||||||
lowerCaseKey := strings.ToLower(k)
|
lowerCaseKey := strings.ToLower(k)
|
||||||
if _, ok := signed[lowerCaseKey]; ok {
|
if _, ok := signed[lowerCaseKey]; ok {
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
// This is https://github.com/aws/aws-sdk-go-v2/blob/a2b751d1ba71f59175a41f9cae5f159f1044360f/aws/signer/v4/v4_test.go
|
// This is https://github.com/aws/aws-sdk-go-v2/blob/a2b751d1ba71f59175a41f9cae5f159f1044360f/aws/signer/v4/v4_test.go
|
||||||
|
// with changes:
|
||||||
|
// * don't duplicate content-length as signed header
|
||||||
|
|
||||||
package v4
|
package v4
|
||||||
|
|
||||||
|
@ -61,6 +63,7 @@ func buildRequestWithBodyReader(serviceName, region string, body io.Reader) (*ht
|
||||||
|
|
||||||
func TestPresignRequest(t *testing.T) {
|
func TestPresignRequest(t *testing.T) {
|
||||||
req, body := buildRequest("dynamodb", "us-east-1", "{}")
|
req, body := buildRequest("dynamodb", "us-east-1", "{}")
|
||||||
|
req.Header.Set("Content-Length", "2")
|
||||||
|
|
||||||
query := req.URL.Query()
|
query := req.URL.Query()
|
||||||
query.Set("X-Amz-Expires", "300")
|
query.Set("X-Amz-Expires", "300")
|
||||||
|
@ -113,6 +116,7 @@ func TestPresignRequest(t *testing.T) {
|
||||||
func TestPresignBodyWithArrayRequest(t *testing.T) {
|
func TestPresignBodyWithArrayRequest(t *testing.T) {
|
||||||
req, body := buildRequest("dynamodb", "us-east-1", "{}")
|
req, body := buildRequest("dynamodb", "us-east-1", "{}")
|
||||||
req.URL.RawQuery = "Foo=z&Foo=o&Foo=m&Foo=a"
|
req.URL.RawQuery = "Foo=z&Foo=o&Foo=m&Foo=a"
|
||||||
|
req.Header.Set("Content-Length", "2")
|
||||||
|
|
||||||
query := req.URL.Query()
|
query := req.URL.Query()
|
||||||
query.Set("X-Amz-Expires", "300")
|
query.Set("X-Amz-Expires", "300")
|
||||||
|
@ -164,6 +168,7 @@ func TestPresignBodyWithArrayRequest(t *testing.T) {
|
||||||
|
|
||||||
func TestSignRequest(t *testing.T) {
|
func TestSignRequest(t *testing.T) {
|
||||||
req, body := buildRequest("dynamodb", "us-east-1", "{}")
|
req, body := buildRequest("dynamodb", "us-east-1", "{}")
|
||||||
|
req.Header.Set("Content-Length", "2")
|
||||||
signer := NewSigner()
|
signer := NewSigner()
|
||||||
err := signer.SignHTTP(context.Background(), testCredentials, req, body, "dynamodb", "us-east-1", time.Unix(0, 0))
|
err := signer.SignHTTP(context.Background(), testCredentials, req, body, "dynamodb", "us-east-1", time.Unix(0, 0))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
Loading…
Reference in a new issue