Nikita Zinkevich
f6a7beb2b5
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>
101 lines
2.7 KiB
Go
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
|
|
}
|