frostfs-s3-gw/playback/request.go
Nikita Zinkevich f6a7beb2b5 [#369] Move playback source files
Move git.frostfs.info/TrueCloudLab/frostfs-s3-gw/cmd/frostfs-s3-playback/request package to git.frostfs.info/TrueCloudLab/frostfs-s3-gw/playback.
Move playback.yaml example config to root config folder.

Signed-off-by: Nikita Zinkevich <n.zinkevich@yadro.com>
2024-08-02 16:51:10 +03:00

101 lines
2.7 KiB
Go

package playback
import (
"context"
"errors"
"net/http"
"net/url"
"regexp"
"strings"
"time"
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api"
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/auth"
v4 "github.com/aws/aws-sdk-go-v2/aws/signer/v4"
"github.com/aws/aws-sdk-go-v2/credentials"
)
var (
// authorizationFieldRegexp -- is regexp for credentials with Base58 encoded cid and oid and '0' (zero) as delimiter.
authorizationFieldRegexp = regexp.MustCompile(`AWS4-HMAC-SHA256 Credential=(?P<access_key_id>[^/]+)/(?P<date>[^/]+)/(?P<region>[^/]*)/(?P<service>[^/]+)/aws4_request,\s*SignedHeaders=(?P<signed_header_fields>.+),\s*Signature=(?P<v4_signature>.+)`)
ErrNoMatches = errors.New("no matches found")
)
type (
LoggedRequest struct {
From string `json:"from"`
URI string `json:"URI"`
Method string `json:"method"`
Query url.Values `json:"query"`
Body []byte `json:"body"`
Header http.Header `json:"headers"`
Response []byte `json:"response"`
}
Credentials struct {
AccessKey string
SecretKey string
}
contextKey struct{}
multipartKey struct{}
)
func SetCredentials(ctx context.Context, accessKey, secretKey string) context.Context {
return context.WithValue(ctx, contextKey{},
Credentials{
AccessKey: accessKey, SecretKey: secretKey,
},
)
}
func GetCredentials(ctx context.Context) (Credentials, error) {
val, ok := ctx.Value(contextKey{}).(Credentials)
if !ok {
return val, errors.New("credentials not set")
}
return val, nil
}
// Sign replace Authorization header with new Access key id and Signature values.
func Sign(ctx context.Context, r *http.Request) error {
creds, err := GetCredentials(ctx)
if err != nil {
return errors.New("failed to get credentials")
}
credProvider, err := credentials.NewStaticCredentialsProvider(creds.AccessKey,
creds.SecretKey, "").Retrieve(ctx)
if err != nil {
return err
}
authInfo, err := parseAuthHeader(r.Header.Get(auth.AuthorizationHdr))
if err != nil {
return err
}
r.Header[auth.AuthorizationHdr][0] = strings.Replace(r.Header[auth.AuthorizationHdr][0],
authInfo["access_key_id"], creds.AccessKey, 1)
signer := v4.NewSigner()
signatureDateTimeStr := r.Header.Get(api.AmzDate)
signatureDateTime, err := time.Parse("20060102T150405Z", signatureDateTimeStr)
if err != nil {
return err
}
err = signer.SignHTTP(ctx, credProvider, r, r.Header.Get(api.AmzContentSha256),
authInfo["service"], authInfo["region"], signatureDateTime)
if err != nil {
return err
}
return nil
}
func parseAuthHeader(authHeader string) (map[string]string, error) {
authInfo := auth.NewRegexpMatcher(authorizationFieldRegexp).GetSubmatches(authHeader)
if len(authInfo) == 0 {
return nil, ErrNoMatches
}
return authInfo, nil
}