All checks were successful
/ DCO (pull_request) Successful in 32s
/ Vulncheck (pull_request) Successful in 1m6s
/ Builds (pull_request) Successful in 1m34s
/ OCI image (pull_request) Successful in 2m2s
/ Lint (pull_request) Successful in 2m10s
/ Tests (pull_request) Successful in 1m17s
/ Vulncheck (push) Successful in 1m6s
/ Builds (push) Successful in 1m6s
/ Lint (push) Successful in 1m57s
/ Tests (push) Successful in 1m20s
/ OCI image (push) Successful in 2m10s
Signed-off-by: Denis Kirillov <d.kirillov@yadro.com>
237 lines
7.7 KiB
Go
237 lines
7.7 KiB
Go
package handler
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"fmt"
|
|
"io"
|
|
"net/http"
|
|
"strconv"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/middleware"
|
|
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func TestSigV4AChunkedReader(t *testing.T) {
|
|
t.Run("with trailers", func(t *testing.T) {
|
|
accessKeyID := "9uEm8zMrGWsEDWiPCnVuQLKTiGtCEXpYXt8eBG7agupw0JDySJZMFuej7PTcPzRqBUyPtFowNu1RtvHULU8XHjie6"
|
|
secretKey := "9f546428957ed7e189b7be928906ce7d1d9cb3042dd4d2d5194e28ce8c4c3b8e"
|
|
|
|
chunk1 := "Testing with the {sdk-java}"
|
|
body := "1b;chunk-signature=3045022100956ca03d2166100b455b532de542892f73925fbcea2f6498674a39a61bb4860902202977c1d47aea548d434540f89640ce97e605d18353cbbd75a619874f02e3dd22**\r\n" +
|
|
chunk1 +
|
|
"\r\n0;chunk-signature=304502210097dcc1721675469910ef8712fc2af0678eb90c12216dd6228c6b621fb6f805a0022047d27d21ae2af8a8172f2ef83c81ce9d4746aa88fc9ee0ca783eaa5e71aaef6c**\r\n" +
|
|
"x-amz-checksum-crc32:Np6zMg==\r\n" +
|
|
"x-amz-trailer-signature:304502200ecacd9aa2c432af5a2327c22a2ff9b32f44ab8559de00309219aef105eaaac102210092cbc0e78c4bcd56490a73da8ceed1934be80f3affeffb14d8c743fc292dda4f**\r\n\r\n"
|
|
|
|
reqBody := bytes.NewBufferString(body)
|
|
req, err := http.NewRequest("PUT", "https://localhost:8184/test2/tmp", reqBody)
|
|
require.NoError(t, err)
|
|
req.Header.Set("x-amz-trailer", "x-amz-checksum-crc32")
|
|
|
|
signature := "3045022100ddbc6ab11785d7f23d299de7db97379116f543377a44e38170a4e43b38b0d62b02201d8dca13c67f04f45491345152db4b704768eb8bb89b5215fd59bb4a4d9d7b61"
|
|
signingTime, err := time.Parse("20060102T150405Z", "20250203T144621Z")
|
|
require.NoError(t, err)
|
|
|
|
key, err := keys.NewPrivateKey()
|
|
require.NoError(t, err)
|
|
|
|
accessBox, err := newTestAccessBox(key)
|
|
require.NoError(t, err)
|
|
accessBox.Gate.SecretKey = secretKey
|
|
|
|
ctx := middleware.SetBox(req.Context(), &middleware.Box{
|
|
AccessBox: accessBox,
|
|
AuthHeaders: &middleware.AuthHeader{
|
|
AccessKeyID: accessKeyID,
|
|
SignatureV4: signature,
|
|
},
|
|
ClientTime: signingTime,
|
|
})
|
|
req = req.WithContext(ctx)
|
|
|
|
r, err := newSignV4aChunkedReader(req)
|
|
require.NoError(t, err)
|
|
|
|
data, err := io.ReadAll(r)
|
|
require.NoError(t, err)
|
|
require.Equal(t, chunk1, string(data))
|
|
})
|
|
|
|
t.Run("without trailers", func(t *testing.T) {
|
|
accessKeyID := "2XEbqH4M3ym7a3E3esxfZ2gRLnMwDXrCN4y1SkQg5fHa09sThVmVL3EE6xeKsyMzaqu5jPi41YCaVbnwbwCTF3bx1"
|
|
secretKey := "00637f53f842573aaa06c2164c598973cd986880987111416cf71f1619def537"
|
|
|
|
chunk1 := "Testing with the {sdk-java}"
|
|
reqBody := bytes.NewBufferString("1b;chunk-signature=3045022100b63692a1b20759bdabd342011823427a8952df75c93174d98ad043abca8052e002201695228a91ba986171b8d0ad20856d3d94ca3614d0a90a50a531ba8e52447b9b**\r\n")
|
|
_, err := reqBody.WriteString(chunk1)
|
|
require.NoError(t, err)
|
|
_, err = reqBody.WriteString("\r\n0;chunk-signature=30440220455885a2d4e9f705256ca6b0a5a22f7f784780ccbd1c0a371e5db3059c91745b022073259dd44746cbd63261d628a04d25be5a32a974c077c5c2d83c8157fb323b9f****\r\n\r\n")
|
|
require.NoError(t, err)
|
|
|
|
req, err := http.NewRequest("PUT", "http://localhost:8084/test/tmp", reqBody)
|
|
require.NoError(t, err)
|
|
|
|
signature := "30440220574244c5ff5deba388c4e3b0541a42113179b6839b3e6b4212d255a118fa9089022056f7b9b72c93f67dbcd25fe9ca67950b5913fc00bb7a62bc276c21e828c0b6c7"
|
|
signingTime, err := time.Parse("20060102T150405Z", "20240904T133253Z")
|
|
require.NoError(t, err)
|
|
|
|
key, err := keys.NewPrivateKey()
|
|
require.NoError(t, err)
|
|
|
|
accessBox, err := newTestAccessBox(key)
|
|
require.NoError(t, err)
|
|
accessBox.Gate.SecretKey = secretKey
|
|
|
|
ctx := middleware.SetBox(req.Context(), &middleware.Box{
|
|
AccessBox: accessBox,
|
|
AuthHeaders: &middleware.AuthHeader{
|
|
AccessKeyID: accessKeyID,
|
|
SignatureV4: signature,
|
|
},
|
|
ClientTime: signingTime,
|
|
})
|
|
req = req.WithContext(ctx)
|
|
|
|
r, err := newSignV4aChunkedReader(req)
|
|
require.NoError(t, err)
|
|
|
|
data, err := io.ReadAll(r)
|
|
require.NoError(t, err)
|
|
require.Equal(t, chunk1, string(data))
|
|
})
|
|
}
|
|
|
|
func TestSigV4ChunkedReader(t *testing.T) {
|
|
accessKeyID := "9uEm8zMrGWsEDWiPCnVuQLKTiGtCEXpYXt8eBG7agupw0JDySJZMFuej7PTcPzRqBUyPtFowNu1RtvHULU8XHjie6"
|
|
secretKey := "9f546428957ed7e189b7be928906ce7d1d9cb3042dd4d2d5194e28ce8c4c3b8e"
|
|
|
|
signature := "b740b3b2a08c541c3fc4bd155a448e25408b509a29af98a86356b894930b93e8"
|
|
signingTime, err := time.Parse("20060102T150405Z", "20250203T134442Z")
|
|
require.NoError(t, err)
|
|
|
|
key, err := keys.NewPrivateKey()
|
|
require.NoError(t, err)
|
|
|
|
accessBox, err := newTestAccessBox(key)
|
|
require.NoError(t, err)
|
|
accessBox.Gate.SecretKey = secretKey
|
|
|
|
setBoxFn := func(ctx context.Context) context.Context {
|
|
return middleware.SetBox(ctx, &middleware.Box{
|
|
AccessBox: accessBox,
|
|
AuthHeaders: &middleware.AuthHeader{
|
|
AccessKeyID: accessKeyID,
|
|
SignatureV4: signature,
|
|
Region: "us-east-1",
|
|
},
|
|
ClientTime: signingTime,
|
|
})
|
|
}
|
|
|
|
chunk1 := "Testing with the {sdk-java}"
|
|
|
|
t.Run("with trailers", func(t *testing.T) {
|
|
body := "1b;chunk-signature=a6a9be5fff05db0b542aedb2203d892b4162250885d06b1422b173ee0ea92ba5\r\n" +
|
|
chunk1 +
|
|
"\r\n0;chunk-signature=31afd083a57c416c46afaf101649d7f0c6c0627cfa60c0f93d1f7ea84396ee42\r\n" +
|
|
"x-amz-checksum-crc32:Np6zMg==\r\n" +
|
|
"x-amz-trailer-signature:40ec0046ac730fa27a1451d00d849056c49553ee753f5d158306d05671a42125\r\n\r\n"
|
|
|
|
reqBody := bytes.NewBufferString(body)
|
|
req, err := http.NewRequest("PUT", "https://localhost:8184/test2/tmp", reqBody)
|
|
require.NoError(t, err)
|
|
req.Header.Set("x-amz-trailer", "x-amz-checksum-crc32")
|
|
|
|
req = req.WithContext(setBoxFn(req.Context()))
|
|
|
|
r, err := newSignV4ChunkedReader(req)
|
|
require.NoError(t, err)
|
|
|
|
data, err := io.ReadAll(r)
|
|
require.NoError(t, err)
|
|
require.Equal(t, chunk1, string(data))
|
|
})
|
|
|
|
t.Run("without trailers", func(t *testing.T) {
|
|
body := "1b;chunk-signature=a6a9be5fff05db0b542aedb2203d892b4162250885d06b1422b173ee0ea92ba5\r\n" +
|
|
chunk1 +
|
|
"\r\n0;chunk-signature=31afd083a57c416c46afaf101649d7f0c6c0627cfa60c0f93d1f7ea84396ee42\r\n\r\n"
|
|
reqBody := bytes.NewBufferString(body)
|
|
req, err := http.NewRequest("PUT", "https://localhost:8184/test2/tmp", reqBody)
|
|
require.NoError(t, err)
|
|
|
|
req = req.WithContext(setBoxFn(req.Context()))
|
|
|
|
r, err := newSignV4ChunkedReader(req)
|
|
require.NoError(t, err)
|
|
|
|
data, err := io.ReadAll(r)
|
|
require.NoError(t, err)
|
|
require.Equal(t, chunk1, string(data))
|
|
})
|
|
}
|
|
|
|
func TestUnsignedChunkReader(t *testing.T) {
|
|
chunk1 := "chunk1"
|
|
chunk2 := "chunk2"
|
|
|
|
t.Run("with trailer", func(t *testing.T) {
|
|
chunks := []string{chunk1, chunk2}
|
|
trailer := map[string]string{"x-amz-checksum-crc64nvme": "q1EYl4rI0TU="}
|
|
body, expected := getChunkedBody(t, chunks, trailer)
|
|
|
|
r, err := newUnsignedChunkedReader(body)
|
|
require.NoError(t, err)
|
|
|
|
data, err := io.ReadAll(r)
|
|
require.NoError(t, err)
|
|
require.Equal(t, expected, string(data))
|
|
|
|
require.EqualValues(t, trailer, r.TrailerHeaders())
|
|
})
|
|
|
|
t.Run("without trailer", func(t *testing.T) {
|
|
chunks := []string{chunk1, chunk2}
|
|
body, expected := getChunkedBody(t, chunks, nil)
|
|
|
|
r, err := newUnsignedChunkedReader(body)
|
|
require.NoError(t, err)
|
|
|
|
data, err := io.ReadAll(r)
|
|
require.NoError(t, err)
|
|
require.Equal(t, expected, string(data))
|
|
})
|
|
}
|
|
|
|
func getChunkedBody(t *testing.T, chunks []string, trailers map[string]string) (*bytes.Buffer, string) {
|
|
res := bytes.NewBufferString("")
|
|
|
|
for i, chunk := range chunks {
|
|
meta := strconv.FormatInt(int64(len(chunk)), 16) + "\r\n"
|
|
if i != 0 {
|
|
meta = "\r\n" + meta
|
|
}
|
|
_, err := res.WriteString(meta)
|
|
require.NoError(t, err)
|
|
_, err = res.WriteString(chunk)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
_, err := res.WriteString("\r\n0\r\n")
|
|
require.NoError(t, err)
|
|
|
|
for k, v := range trailers {
|
|
_, err := res.WriteString(fmt.Sprintf("%s:%s\n", k, v))
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
_, err = res.WriteString("\r\n")
|
|
require.NoError(t, err)
|
|
|
|
return res, strings.Join(chunks, "")
|
|
}
|