the unsupported authorization type error only echoed the algorithm back in ArgumentValue, while s3 returns the whole Authorization header there. the parse error now carries the raw header and the s3 error mapping uses it, which also lets the bats test skipped for #1705 run again. Fixes #2489
175 lines
6.0 KiB
Go
175 lines
6.0 KiB
Go
// Copyright 2023 Versity Software
|
|
// This file is licensed under the Apache License, Version 2.0
|
|
// (the "License"); you may not use this file except in compliance
|
|
// with the License. You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing,
|
|
// software distributed under the License is distributed on an
|
|
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
// KIND, either express or implied. See the License for the
|
|
// specific language governing permissions and limitations
|
|
// under the License.
|
|
|
|
package utils
|
|
|
|
import (
|
|
"errors"
|
|
"net"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/gofiber/fiber/v3"
|
|
"github.com/valyala/fasthttp"
|
|
"github.com/valyala/fasthttp/fasthttputil"
|
|
"github.com/versity/versitygw/internal/sigv4auth"
|
|
"github.com/versity/versitygw/s3err"
|
|
)
|
|
|
|
func TestAuthParse(t *testing.T) {
|
|
vectors := []struct {
|
|
name string // name of test string
|
|
authstr string // Authorization string
|
|
algo string
|
|
sig string
|
|
}{
|
|
{
|
|
name: "restic",
|
|
authstr: "AWS4-HMAC-SHA256 Credential=user/20240116/us-east-1/s3/aws4_request,SignedHeaders=content-md5;host;x-amz-content-sha256;x-amz-date;x-amz-decoded-content-length,Signature=d5199fc7f3aa35dd3d400427be2ae4c98bfad390785280cbb9eea015b51e12ac",
|
|
algo: "AWS4-HMAC-SHA256",
|
|
sig: "d5199fc7f3aa35dd3d400427be2ae4c98bfad390785280cbb9eea015b51e12ac",
|
|
},
|
|
{
|
|
name: "aws eaxample",
|
|
authstr: "AWS4-HMAC-SHA256 Credential=AKIAIOSFODNN7EXAMPLE/20130524/us-east-1/s3/aws4_request, SignedHeaders=host;range;x-amz-date, Signature=fe5f80f77d5fa3beca038a248ff027d0445342fe2855ddc963176630326f1024",
|
|
algo: "AWS4-HMAC-SHA256",
|
|
sig: "fe5f80f77d5fa3beca038a248ff027d0445342fe2855ddc963176630326f1024",
|
|
},
|
|
{
|
|
name: "s3browser",
|
|
authstr: "AWS4-HMAC-SHA256 Credential=access_key/20240206/us-east-1/s3/aws4_request,SignedHeaders=host;user-agent;x-amz-content-sha256;x-amz-date, Signature=37a35d96998d786113ad420c57c22c5433f6aca74f88f26566caa047fc3601c6",
|
|
algo: "AWS4-HMAC-SHA256",
|
|
sig: "37a35d96998d786113ad420c57c22c5433f6aca74f88f26566caa047fc3601c6",
|
|
},
|
|
}
|
|
|
|
for _, v := range vectors {
|
|
t.Run(v.name, func(t *testing.T) {
|
|
data, err := ParseAuthorization(v.authstr)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if data.Algorithm != v.algo {
|
|
t.Errorf("algo got %v, expected %v", data.Algorithm, v.algo)
|
|
}
|
|
if data.Signature != v.sig {
|
|
t.Errorf("signature got %v, expected %v", data.Signature, v.sig)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestAuthParseUnsupportedType(t *testing.T) {
|
|
vectors := []struct {
|
|
name string
|
|
authstr string
|
|
}{
|
|
{
|
|
name: "misspelled algorithm",
|
|
authstr: "AWS-HMAC-SHA25 Credential=user/20261007/us-east-1/s3/aws4_request,SignedHeaders=host;x-amz-content-sha256;x-amz-date,Signature=4a2a292c73c80d2fe4a4b9e506fe0d1a8209f92dd2dfd32c27c30402e42b473d",
|
|
},
|
|
{
|
|
name: "spaces between components",
|
|
authstr: "AWS2-HMAC-SHA1 Credential=user/20261007/us-east-1/s3/aws4_request, SignedHeaders=host;x-amz-date, Signature=4a2a292c73c80d2fe4a4b9e506fe0d1a8209f92dd2dfd32c27c30402e42b473d",
|
|
},
|
|
}
|
|
|
|
for _, v := range vectors {
|
|
t.Run(v.name, func(t *testing.T) {
|
|
_, err := ParseAuthorization(v.authstr)
|
|
want := s3err.GetInvalidArgumentErr(s3err.InvalidArgAuthorizationType, v.authstr)
|
|
if !errors.Is(err, want) {
|
|
t.Errorf("err got %v, expected %v", err, want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
// 2024/02/06 21:03:28 Request headers:
|
|
// 2024/02/06 21:03:28 Host: 172.21.0.160:11000
|
|
// 2024/02/06 21:03:28 User-Agent: S3 Browser/11.5.7 (https://s3browser.com)
|
|
// 2024/02/06 21:03:28 Authorization: AWS4-HMAC-SHA256 Credential=access_key/20240206/us-east-1/s3/aws4_request,SignedHeaders=host;user-agent;x-amz-content-sha256;x-amz-date, Signature=37a35d96998d786113ad420c57c22c5433f6aca74f88f26566caa047fc3601c6
|
|
// 2024/02/06 21:03:28 X-Amz-Content-Sha256: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
|
|
// 2024/02/06 21:03:28 X-Amz-Date: 20240206T210328Z
|
|
func Test_Client_UserAgent(t *testing.T) {
|
|
signedHdrs := []string{"host", "user-agent", "x-amz-content-sha256", "x-amz-date"}
|
|
access := "access_key"
|
|
secret := "secret_key"
|
|
region := "us-east-1"
|
|
host := "172.21.0.160:11000"
|
|
agent := "S3 Browser/11.5.7 (https://s3browser.com)"
|
|
expectedSig := "37a35d96998d786113ad420c57c22c5433f6aca74f88f26566caa047fc3601c6"
|
|
dateStr := "20240206T210328Z"
|
|
|
|
app := fiber.New(fiber.Config{})
|
|
|
|
tdate, err := time.Parse(iso8601Format, dateStr)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
app.Get("/", func(c fiber.Ctx) error {
|
|
auth := sigv4auth.AuthData{
|
|
Access: access,
|
|
Region: region,
|
|
Service: service,
|
|
SignedHeaders: strings.Join(signedHdrs, ";"),
|
|
Signature: expectedSig,
|
|
}
|
|
derivedKey := sigv4auth.DeriveKey(secret, dateStr[:8], region, service)
|
|
opts := sigv4auth.CheckOptions{DisableURIPathEscaping: true}
|
|
contentLen := int64(c.Request().Header.ContentLength())
|
|
|
|
if _, err := sigv4auth.CheckSignature(c, auth, derivedKey, zeroLenSig, tdate, contentLen, opts); err != nil {
|
|
t.Errorf("CheckSignature: %v", err)
|
|
}
|
|
|
|
return c.Send(c.Request().Header.UserAgent())
|
|
})
|
|
|
|
ln := fasthttputil.NewInmemoryListener()
|
|
go func() {
|
|
err := app.Listener(ln)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
}()
|
|
|
|
client := fasthttp.Client{
|
|
Dial: func(_ string) (net.Conn, error) { return ln.Dial() },
|
|
}
|
|
|
|
req := fasthttp.AcquireRequest()
|
|
resp := fasthttp.AcquireResponse()
|
|
defer fasthttp.ReleaseRequest(req)
|
|
defer fasthttp.ReleaseResponse(resp)
|
|
|
|
// Host/User-Agent/X-Amz-Content-Sha256/X-Amz-Date are sent as real
|
|
// headers, reproducing the captured request verbatim, so CheckSignature
|
|
// extracts them straight off the live fiber.Ctx like it does for any
|
|
// real request.
|
|
req.SetRequestURI("http://" + host + "/")
|
|
req.Header.SetUserAgent(agent)
|
|
req.Header.Set("X-Amz-Content-Sha256", zeroLenSig)
|
|
req.Header.Set("X-Amz-Date", dateStr)
|
|
if err := client.Do(req, resp); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if got := string(resp.Body()); got != agent {
|
|
t.Errorf("user-agent got %q, expected %q", got, agent)
|
|
}
|
|
}
|