diff --git a/api/auth/center_test.go b/api/auth/center_test.go index 807bdd17..c4756466 100644 --- a/api/auth/center_test.go +++ b/api/auth/center_test.go @@ -139,6 +139,45 @@ Testing with the {sdk-java} 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) { defaultErr := errors.GetAPIError(errors.ErrContentSHA256Mismatch) diff --git a/api/auth/signer/v4sdk2/signer/v4/v4.go b/api/auth/signer/v4sdk2/signer/v4/v4.go index 5ea9a185..7595e175 100644 --- a/api/auth/signer/v4sdk2/signer/v4/v4.go +++ b/api/auth/signer/v4sdk2/signer/v4/v4.go @@ -1,6 +1,7 @@ // This is https://github.com/aws/aws-sdk-go-v2/blob/a2b751d1ba71f59175a41f9cae5f159f1044360f/aws/signer/v4/v4.go // with changes: // * using different headers for sign/presign +// * don't duplicate content-length as signed header // * use copy of smithy-go encoding/httpbinding package // * use zap.Logger instead of smithy-go/logging @@ -54,7 +55,6 @@ import ( "net/textproto" "net/url" "sort" - "strconv" "strings" "time" @@ -440,20 +440,20 @@ func (s *httpSigner) buildCanonicalHeaders(host string, rule v4Internal.Rule, he headers = append(headers, hostHeader) signed[hostHeader] = append(signed[hostHeader], host) - const contentLengthHeader = "content-length" - if length > 0 { - headers = append(headers, contentLengthHeader) - signed[contentLengthHeader] = append(signed[contentLengthHeader], strconv.FormatInt(length, 10)) - } + //const contentLengthHeader = "content-length" + //if length > 0 { + // headers = append(headers, contentLengthHeader) + // signed[contentLengthHeader] = append(signed[contentLengthHeader], strconv.FormatInt(length, 10)) + //} for k, v := range header { if !rule.IsValid(k) { continue // ignored header } - if strings.EqualFold(k, contentLengthHeader) { - // prevent signing already handled content-length header. - continue - } + //if strings.EqualFold(k, contentLengthHeader) { + // // prevent signing already handled content-length header. + // continue + //} lowerCaseKey := strings.ToLower(k) if _, ok := signed[lowerCaseKey]; ok { diff --git a/api/auth/signer/v4sdk2/signer/v4/v4_test.go b/api/auth/signer/v4sdk2/signer/v4/v4_test.go index fb7b7d10..9065903a 100644 --- a/api/auth/signer/v4sdk2/signer/v4/v4_test.go +++ b/api/auth/signer/v4sdk2/signer/v4/v4_test.go @@ -1,4 +1,6 @@ // 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 @@ -61,6 +63,7 @@ func buildRequestWithBodyReader(serviceName, region string, body io.Reader) (*ht func TestPresignRequest(t *testing.T) { req, body := buildRequest("dynamodb", "us-east-1", "{}") + req.Header.Set("Content-Length", "2") query := req.URL.Query() query.Set("X-Amz-Expires", "300") @@ -113,6 +116,7 @@ func TestPresignRequest(t *testing.T) { func TestPresignBodyWithArrayRequest(t *testing.T) { req, body := buildRequest("dynamodb", "us-east-1", "{}") req.URL.RawQuery = "Foo=z&Foo=o&Foo=m&Foo=a" + req.Header.Set("Content-Length", "2") query := req.URL.Query() query.Set("X-Amz-Expires", "300") @@ -164,6 +168,7 @@ func TestPresignBodyWithArrayRequest(t *testing.T) { func TestSignRequest(t *testing.T) { req, body := buildRequest("dynamodb", "us-east-1", "{}") + req.Header.Set("Content-Length", "2") signer := NewSigner() err := signer.SignHTTP(context.Background(), testCredentials, req, body, "dynamodb", "us-east-1", time.Unix(0, 0)) if err != nil {