diff --git a/s3api/utils/auth-reader.go b/s3api/utils/auth-reader.go index 03248352..4b9c2194 100644 --- a/s3api/utils/auth-reader.go +++ b/s3api/utils/auth-reader.go @@ -21,6 +21,7 @@ import ( "os" "strings" "time" + "unicode" "github.com/aws/aws-sdk-go-v2/aws" v4 "github.com/aws/aws-sdk-go-v2/aws/signer/v4" @@ -173,18 +174,20 @@ func ParseAuthorization(authorization string) (AuthData, error) { // authorization must start with: // Authorization: // followed by key=value pairs separated by "," - authParts := strings.Fields(authorization) + authParts := strings.SplitN(authorization, " ", 2) for i, el := range authParts { - authParts[i] = strings.TrimSpace(el) + if strings.Contains(el, " ") { + authParts[i] = removeSpace(el) + } } - if len(authParts) < 3 { + if len(authParts) < 2 { return a, s3err.GetAPIError(s3err.ErrMissingFields) } algo := authParts[0] - kvData := strings.Join(authParts[1:], "") + kvData := authParts[1] kvPairs := strings.Split(kvData, ",") // we are expecting at least Credential, SignedHeaders, and Signature // key value pairs here @@ -244,6 +247,17 @@ func ParseAuthorization(authorization string) (AuthData, error) { }, nil } +func removeSpace(str string) string { + var b strings.Builder + b.Grow(len(str)) + for _, ch := range str { + if !unicode.IsSpace(ch) { + b.WriteRune(ch) + } + } + return b.String() +} + var ( specialValues = map[string]bool{ "UNSIGNED-PAYLOAD": true, diff --git a/s3api/utils/auth_test.go b/s3api/utils/auth_test.go new file mode 100644 index 00000000..107ce9e8 --- /dev/null +++ b/s3api/utils/auth_test.go @@ -0,0 +1,40 @@ +package utils + +import ( + "testing" +) + +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", + }} + + 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) + } + }) + } +}