forked from TrueCloudLab/frostfs-s3-gw
[#656] Don't ignore Expect header in sigv4
Signed-off-by: Denis Kirillov <d.kirillov@yadro.com>
This commit is contained in:
parent
079fd20513
commit
1fac8e3ef2
4 changed files with 78 additions and 7 deletions
|
@ -40,6 +40,9 @@ var (
|
||||||
postPolicyCredentialRegexp = regexp.MustCompile(`(?P<access_key_id>[^/]+)/(?P<date>[^/]+)/(?P<region>[^/]*)/(?P<service>[^/]+)/aws4_request`)
|
postPolicyCredentialRegexp = regexp.MustCompile(`(?P<access_key_id>[^/]+)/(?P<date>[^/]+)/(?P<region>[^/]*)/(?P<service>[^/]+)/aws4_request`)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// need for tests.
|
||||||
|
var timeNow = time.Now
|
||||||
|
|
||||||
type (
|
type (
|
||||||
Center struct {
|
Center struct {
|
||||||
reg *RegexpSubmatcher
|
reg *RegexpSubmatcher
|
||||||
|
@ -470,7 +473,7 @@ func (c *Center) checkSign(ctx context.Context, authHeader *AuthHeader, box *acc
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkPresignedDate(authHeader *AuthHeader, signatureDateTime time.Time) error {
|
func checkPresignedDate(authHeader *AuthHeader, signatureDateTime time.Time) error {
|
||||||
now := time.Now()
|
now := timeNow()
|
||||||
if signatureDateTime.Add(authHeader.Expiration).Before(now) {
|
if signatureDateTime.Add(authHeader.Expiration).Before(now) {
|
||||||
return fmt.Errorf("%w: expired: now %s, signature %s", apierr.GetAPIError(apierr.ErrExpiredPresignRequest),
|
return fmt.Errorf("%w: expired: now %s, signature %s", apierr.GetAPIError(apierr.ErrExpiredPresignRequest),
|
||||||
now.Format(time.RFC3339), signatureDateTime.Format(time.RFC3339))
|
now.Format(time.RFC3339), signatureDateTime.Format(time.RFC3339))
|
||||||
|
|
|
@ -182,6 +182,71 @@ func TestSignatureV4(t *testing.T) {
|
||||||
require.Equal(t, signature, signatureComputed, "signature mismatched")
|
require.Equal(t, signature, signatureComputed, "signature mismatched")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestSignExpectHeader(t *testing.T) {
|
||||||
|
timeNow = func() time.Time {
|
||||||
|
return time.Date(2025, 3, 10, 11, 0, 0, 0, time.UTC)
|
||||||
|
}
|
||||||
|
t.Cleanup(func() {
|
||||||
|
timeNow = time.Now
|
||||||
|
})
|
||||||
|
|
||||||
|
ctx := context.Background()
|
||||||
|
key, err := keys.NewPrivateKey()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
cfg := &cache.Config{
|
||||||
|
Size: 10,
|
||||||
|
Lifetime: 24 * time.Hour,
|
||||||
|
Logger: zaptest.NewLogger(t),
|
||||||
|
}
|
||||||
|
|
||||||
|
gateData := []*accessbox.GateData{{
|
||||||
|
BearerToken: &bearer.Token{},
|
||||||
|
GateKey: key.PublicKey(),
|
||||||
|
}}
|
||||||
|
|
||||||
|
accessBox, _, err := accessbox.PackTokens(gateData, []byte("0a85c05b993e7663bdd245aa780569ee8abbdc1d9d9a9e185395ff87dffb0105"), true)
|
||||||
|
require.NoError(t, err)
|
||||||
|
data, err := accessBox.Marshal()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
var obj object.Object
|
||||||
|
obj.SetPayload(data)
|
||||||
|
var addr oid.Address
|
||||||
|
err = addr.DecodeString("2t6v52sJdxN2NV2bFfYnuTSQiYkbcDQ2yMKHfGSsjHiv/HbUvXKFK7meCQWoo1Es3oGSMQFbFK7Np82JVEMbCM48d")
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
frostfs := newFrostFSMock()
|
||||||
|
frostfs.objects[getAccessKeyID(addr)] = &obj
|
||||||
|
|
||||||
|
tknCfg := tokens.Config{
|
||||||
|
FrostFS: frostfs,
|
||||||
|
Key: key,
|
||||||
|
CacheConfig: cfg,
|
||||||
|
}
|
||||||
|
creds := tokens.New(tknCfg)
|
||||||
|
cntr := New(creds, nil, ¢erSettingsMock{})
|
||||||
|
|
||||||
|
body := bytes.NewBufferString("")
|
||||||
|
|
||||||
|
req, err := http.NewRequest("PUT", "http://localhost:8184/test/tmp.txt", body)
|
||||||
|
require.NoError(t, err)
|
||||||
|
req.Header.Set("Authorization", "AWS4-HMAC-SHA256 Credential=2t6v52sJdxN2NV2bFfYnuTSQiYkbcDQ2yMKHfGSsjHiv0HbUvXKFK7meCQWoo1Es3oGSMQFbFK7Np82JVEMbCM48d/20250310/us-east-2/s3/aws4_request, SignedHeaders=expect;host;x-amz-content-sha256;x-amz-date, Signature=966bda3d22213ae3f10d82b302041d2fc1c18804e8c02ca7d9bd35b6bcb8c161")
|
||||||
|
req.Header.Set("Expect", "100-continue")
|
||||||
|
req.Header.Set("X-Amz-Content-Sha256", UnsignedPayload)
|
||||||
|
req.Header.Set("X-Amz-Date", "20250310T082808Z")
|
||||||
|
|
||||||
|
_, err = cntr.Authenticate(ctx, req)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
req2, err := http.NewRequest("PUT", "http://localhost:8184/test/tmp.txt?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=2t6v52sJdxN2NV2bFfYnuTSQiYkbcDQ2yMKHfGSsjHiv0HbUvXKFK7meCQWoo1Es3oGSMQFbFK7Np82JVEMbCM48d%2F20250310%2Fru%2Fs3%2Faws4_request&X-Amz-Date=20250310T083436Z&X-Amz-Expires=43200&X-Amz-SignedHeaders=expect%3Bhost&X-Amz-Signature=42c3dbe45842fdfd62d78632e135f5460e3f709ab6b949e257de30168946859b", body)
|
||||||
|
require.NoError(t, err)
|
||||||
|
req2.Header.Set("Expect", "100-continue")
|
||||||
|
|
||||||
|
_, err = cntr.Authenticate(ctx, req2)
|
||||||
|
require.NoError(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
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/internal/v4/header.go
|
// This is https://github.com/aws/aws-sdk-go-v2/blob/a2b751d1ba71f59175a41f9cae5f159f1044360f/aws/signer/internal/v4/header.go
|
||||||
// with changes:
|
// with changes:
|
||||||
// * drop User-Agent header from ignored
|
// * drop User-Agent header from ignored
|
||||||
|
// * drop Expect header from ignored
|
||||||
|
|
||||||
package v4
|
package v4
|
||||||
|
|
||||||
|
@ -11,7 +12,7 @@ var IgnoredPresignedHeaders = Rules{
|
||||||
"Authorization": struct{}{},
|
"Authorization": struct{}{},
|
||||||
"User-Agent": struct{}{},
|
"User-Agent": struct{}{},
|
||||||
"X-Amzn-Trace-Id": struct{}{},
|
"X-Amzn-Trace-Id": struct{}{},
|
||||||
"Expect": struct{}{},
|
//"Expect": struct{}{},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -24,7 +25,7 @@ var IgnoredHeaders = Rules{
|
||||||
"Authorization": struct{}{},
|
"Authorization": struct{}{},
|
||||||
//"User-Agent": struct{}{},
|
//"User-Agent": struct{}{},
|
||||||
"X-Amzn-Trace-Id": struct{}{},
|
"X-Amzn-Trace-Id": struct{}{},
|
||||||
"Expect": struct{}{},
|
//"Expect": struct{}{},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
// This is https://github.com/aws/aws-sdk-go-v2/blob/a2b751d1ba71f59175a41f9cae5f159f1044360f/aws/signer/internal/v4/header_test.go
|
// This is https://github.com/aws/aws-sdk-go-v2/blob/a2b751d1ba71f59175a41f9cae5f159f1044360f/aws/signer/internal/v4/header_test.go
|
||||||
|
// with changes:
|
||||||
|
// * drop Expect header from ignored
|
||||||
|
|
||||||
package v4
|
package v4
|
||||||
|
|
||||||
|
@ -41,10 +43,10 @@ func TestIgnoredHeaders(t *testing.T) {
|
||||||
Header string
|
Header string
|
||||||
ExpectIgnored bool
|
ExpectIgnored bool
|
||||||
}{
|
}{
|
||||||
"expect": {
|
//"expect": {
|
||||||
Header: "Expect",
|
// Header: "Expect",
|
||||||
ExpectIgnored: true,
|
// ExpectIgnored: true,
|
||||||
},
|
//},
|
||||||
"authorization": {
|
"authorization": {
|
||||||
Header: "Authorization",
|
Header: "Authorization",
|
||||||
ExpectIgnored: true,
|
ExpectIgnored: true,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue