forked from TrueCloudLab/frostfs-s3-gw
[#339] Fix logging in authmate [pre]sign command
Signed-off-by: Denis Kirillov <d.kirillov@yadro.com>
This commit is contained in:
parent
7bf31bea18
commit
ea714c2e9e
6 changed files with 54 additions and 31 deletions
|
@ -142,10 +142,6 @@ func (c *Center) parseAuthHeader(authHeader string, headers http.Header) (*AuthH
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("%w: %s", apierr.GetAPIError(apierr.ErrAuthorizationHeaderMalformed), authHeader)
|
return nil, fmt.Errorf("%w: %s", apierr.GetAPIError(apierr.ErrAuthorizationHeaderMalformed), authHeader)
|
||||||
}
|
}
|
||||||
// AWS4-ECDSA-P256-SHA256
|
|
||||||
// Credential=2XGRML5EW3LMHdf64W2DkBy1Nkuu4y4wGhUj44QjbXBi05ZNvs8WVwy1XTmSEkcVkydPKzCgtmR7U3zyLYTj3Snxf/20240326/s3/aws4_request,
|
|
||||||
// SignedHeaders=amz-sdk-invocation-id;amz-sdk-request;host;x-amz-content-sha256;x-amz-date;x-amz-region-set,
|
|
||||||
// Signature=3044022006a2bc760140834101d0a79667d6aa75768c1a28e9cafc8963484d0752a6c6050220629dc06d7d6505e1b1e2a5d1f974b25ba32fdffc6f3f70dc4dda31b8a6f7ea2b
|
|
||||||
|
|
||||||
return &AuthHeader{
|
return &AuthHeader{
|
||||||
AccessKeyID: submatches["access_key_id"],
|
AccessKeyID: submatches["access_key_id"],
|
||||||
|
@ -487,20 +483,19 @@ func SignStr(secret, service, region string, t time.Time, strToSign string) stri
|
||||||
return hex.EncodeToString(signature)
|
return hex.EncodeToString(signature)
|
||||||
}
|
}
|
||||||
|
|
||||||
func SignStrV4A(cred aws.Credentials, strToSign string) (string, error) {
|
func SignStrV4A(ctx context.Context, cred aws.Credentials, strToSign string) (string, error) {
|
||||||
hash := sha256.New()
|
|
||||||
hash.Write([]byte(strToSign))
|
|
||||||
|
|
||||||
credAdapter := v4a.SymmetricCredentialAdaptor{
|
credAdapter := v4a.SymmetricCredentialAdaptor{
|
||||||
SymmetricProvider: credentials.NewStaticCredentialsProvider(cred.AccessKeyID, cred.SecretAccessKey, ""),
|
SymmetricProvider: credentials.NewStaticCredentialsProvider(cred.AccessKeyID, cred.SecretAccessKey, ""),
|
||||||
}
|
}
|
||||||
|
|
||||||
creds, err := credAdapter.RetrievePrivateKey(context.Background()) // because of using StaticCredentialsProvider
|
creds, err := credAdapter.RetrievePrivateKey(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// no error is expected
|
return "", err
|
||||||
panic(err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hash := sha256.New()
|
||||||
|
hash.Write([]byte(strToSign))
|
||||||
|
|
||||||
sig, err := creds.PrivateKey.Sign(rand.Reader, hash.Sum(nil), crypto.SHA256)
|
sig, err := creds.PrivateKey.Sign(rand.Reader, hash.Sum(nil), crypto.SHA256)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
|
|
|
@ -13,6 +13,7 @@ import (
|
||||||
oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id"
|
oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id"
|
||||||
"github.com/aws/aws-sdk-go-v2/aws"
|
"github.com/aws/aws-sdk-go-v2/aws"
|
||||||
utils "github.com/trailofbits/go-fuzz-utils"
|
utils "github.com/trailofbits/go-fuzz-utils"
|
||||||
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -60,7 +61,7 @@ func DoFuzzAuthenticate(input []byte) int {
|
||||||
SignTime: time.Now().UTC(),
|
SignTime: time.Now().UTC(),
|
||||||
}
|
}
|
||||||
|
|
||||||
req, err := PresignRequest(context.Background(), awsCreds, reqData, presignData)
|
req, err := PresignRequest(context.Background(), awsCreds, reqData, presignData, zap.NewNop())
|
||||||
if req == nil {
|
if req == nil {
|
||||||
return fuzzFailExitCode
|
return fuzzFailExitCode
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,6 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
@ -16,6 +15,7 @@ import (
|
||||||
"github.com/aws/aws-sdk-go-v2/credentials"
|
"github.com/aws/aws-sdk-go-v2/credentials"
|
||||||
"github.com/aws/smithy-go/encoding/httpbinding"
|
"github.com/aws/smithy-go/encoding/httpbinding"
|
||||||
"github.com/aws/smithy-go/logging"
|
"github.com/aws/smithy-go/logging"
|
||||||
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|
||||||
type RequestData struct {
|
type RequestData struct {
|
||||||
|
@ -34,7 +34,7 @@ type PresignData struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// PresignRequest forms pre-signed request to access objects without aws credentials.
|
// PresignRequest forms pre-signed request to access objects without aws credentials.
|
||||||
func PresignRequest(ctx context.Context, creds aws.Credentials, reqData RequestData, presignData PresignData) (*http.Request, error) {
|
func PresignRequest(ctx context.Context, creds aws.Credentials, reqData RequestData, presignData PresignData, log *zap.Logger) (*http.Request, error) {
|
||||||
urlStr := fmt.Sprintf("%s/%s/%s", reqData.Endpoint, httpbinding.EscapePath(reqData.Bucket, false), httpbinding.EscapePath(reqData.Object, false))
|
urlStr := fmt.Sprintf("%s/%s/%s", reqData.Endpoint, httpbinding.EscapePath(reqData.Bucket, false), httpbinding.EscapePath(reqData.Object, false))
|
||||||
req, err := http.NewRequest(strings.ToUpper(reqData.Method), urlStr, nil)
|
req, err := http.NewRequest(strings.ToUpper(reqData.Method), urlStr, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -49,6 +49,8 @@ func PresignRequest(ctx context.Context, creds aws.Credentials, reqData RequestD
|
||||||
|
|
||||||
signer := v4.NewSigner(func(options *v4.SignerOptions) {
|
signer := v4.NewSigner(func(options *v4.SignerOptions) {
|
||||||
options.DisableURIPathEscaping = true
|
options.DisableURIPathEscaping = true
|
||||||
|
options.LogSigning = true
|
||||||
|
options.Logger = &logWrapper{log: log}
|
||||||
})
|
})
|
||||||
|
|
||||||
signedURI, _, err := signer.PresignHTTP(ctx, creds, req, presignData.Headers[AmzContentSHA256], presignData.Service, presignData.Region, presignData.SignTime)
|
signedURI, _, err := signer.PresignHTTP(ctx, creds, req, presignData.Headers[AmzContentSHA256], presignData.Service, presignData.Region, presignData.SignTime)
|
||||||
|
@ -64,7 +66,7 @@ func PresignRequest(ctx context.Context, creds aws.Credentials, reqData RequestD
|
||||||
}
|
}
|
||||||
|
|
||||||
// PresignRequestV4a forms pre-signed request to access objects without aws credentials.
|
// PresignRequestV4a forms pre-signed request to access objects without aws credentials.
|
||||||
func PresignRequestV4a(cred aws.Credentials, reqData RequestData, presignData PresignData) (*http.Request, error) {
|
func PresignRequestV4a(cred aws.Credentials, reqData RequestData, presignData PresignData, log *zap.Logger) (*http.Request, error) {
|
||||||
urlStr := fmt.Sprintf("%s/%s/%s", reqData.Endpoint, httpbinding.EscapePath(reqData.Bucket, false), httpbinding.EscapePath(reqData.Object, false))
|
urlStr := fmt.Sprintf("%s/%s/%s", reqData.Endpoint, httpbinding.EscapePath(reqData.Bucket, false), httpbinding.EscapePath(reqData.Object, false))
|
||||||
req, err := http.NewRequest(strings.ToUpper(reqData.Method), urlStr, nil)
|
req, err := http.NewRequest(strings.ToUpper(reqData.Method), urlStr, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -76,12 +78,12 @@ func PresignRequestV4a(cred aws.Credentials, reqData RequestData, presignData Pr
|
||||||
}
|
}
|
||||||
|
|
||||||
req.Header.Set(AmzDate, presignData.SignTime.Format("20060102T150405Z"))
|
req.Header.Set(AmzDate, presignData.SignTime.Format("20060102T150405Z"))
|
||||||
req.Header.Set(AmzExpires, strconv.Itoa(int(presignData.Lifetime.Seconds())))
|
req.Header.Set(AmzExpires, strconv.FormatFloat(presignData.Lifetime.Round(time.Second).Seconds(), 'f', 0, 64))
|
||||||
|
|
||||||
signer := v4a.NewSigner(func(options *v4a.SignerOptions) {
|
signer := v4a.NewSigner(func(options *v4a.SignerOptions) {
|
||||||
options.DisableURIPathEscaping = true
|
options.DisableURIPathEscaping = true
|
||||||
options.LogSigning = true
|
options.LogSigning = true
|
||||||
options.Logger = logging.NewStandardLogger(os.Stdout)
|
options.Logger = &logWrapper{log: log}
|
||||||
})
|
})
|
||||||
|
|
||||||
credAdapter := v4a.SymmetricCredentialAdaptor{
|
credAdapter := v4a.SymmetricCredentialAdaptor{
|
||||||
|
@ -97,7 +99,21 @@ func PresignRequestV4a(cred aws.Credentials, reqData RequestData, presignData Pr
|
||||||
return nil, fmt.Errorf("presign: %w", err)
|
return nil, fmt.Errorf("presign: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println(presignedURL)
|
|
||||||
|
|
||||||
return http.NewRequest(reqData.Method, presignedURL, nil)
|
return http.NewRequest(reqData.Method, presignedURL, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type logWrapper struct {
|
||||||
|
log *zap.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *logWrapper) Logf(classification logging.Classification, format string, args ...interface{}) {
|
||||||
|
msg := fmt.Sprintf(format, args...)
|
||||||
|
switch classification {
|
||||||
|
case logging.Warn:
|
||||||
|
l.log.Warn(msg)
|
||||||
|
case logging.Debug:
|
||||||
|
l.log.Debug(msg)
|
||||||
|
default:
|
||||||
|
l.log.Info(msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -20,6 +20,7 @@ import (
|
||||||
credentialsv2 "github.com/aws/aws-sdk-go-v2/credentials"
|
credentialsv2 "github.com/aws/aws-sdk-go-v2/credentials"
|
||||||
"github.com/aws/smithy-go/logging"
|
"github.com/aws/smithy-go/logging"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
"go.uber.org/zap/zaptest"
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ tokens.Credentials = (*credentialsMock)(nil)
|
var _ tokens.Credentials = (*credentialsMock)(nil)
|
||||||
|
@ -83,7 +84,7 @@ func TestCheckSign(t *testing.T) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
req, err := PresignRequest(ctx, awsCreds, reqData, presignData)
|
req, err := PresignRequest(ctx, awsCreds, reqData, presignData, zaptest.NewLogger(t))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
expBox := &accessbox.Box{
|
expBox := &accessbox.Box{
|
||||||
|
@ -131,7 +132,7 @@ func TestCheckSignV4a(t *testing.T) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
req, err := PresignRequestV4a(awsCreds, reqData, presignData)
|
req, err := PresignRequestV4a(awsCreds, reqData, presignData, zaptest.NewLogger(t))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
req.Header.Set(ContentTypeHdr, "text/plain")
|
req.Header.Set(ContentTypeHdr, "text/plain")
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package modules
|
package modules
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
@ -60,6 +61,11 @@ func initGeneratePresignedURLCmd() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func runGeneratePresignedURLCmd(cmd *cobra.Command, _ []string) error {
|
func runGeneratePresignedURLCmd(cmd *cobra.Command, _ []string) error {
|
||||||
|
ctx, cancel := context.WithTimeout(cmd.Context(), viper.GetDuration(timeoutFlag))
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
log := getLogger()
|
||||||
|
|
||||||
var (
|
var (
|
||||||
region string
|
region string
|
||||||
creds aws.Credentials
|
creds aws.Credentials
|
||||||
|
@ -68,16 +74,16 @@ func runGeneratePresignedURLCmd(cmd *cobra.Command, _ []string) error {
|
||||||
profile := viper.GetString(profileFlag)
|
profile := viper.GetString(profileFlag)
|
||||||
|
|
||||||
if profile == "" {
|
if profile == "" {
|
||||||
cfg, err := config.LoadDefaultConfig(cmd.Context())
|
cfg, err := config.LoadDefaultConfig(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return wrapPreparationError(err)
|
return wrapPreparationError(err)
|
||||||
}
|
}
|
||||||
region = cfg.Region
|
region = cfg.Region
|
||||||
if creds, err = cfg.Credentials.Retrieve(cmd.Context()); err != nil {
|
if creds, err = cfg.Credentials.Retrieve(ctx); err != nil {
|
||||||
return wrapPreparationError(fmt.Errorf("couldn't get default aws credentials: %w", err))
|
return wrapPreparationError(fmt.Errorf("couldn't get default aws credentials: %w", err))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
cfg, err := config.LoadSharedConfigProfile(cmd.Context(), viper.GetString(profileFlag))
|
cfg, err := config.LoadSharedConfigProfile(ctx, viper.GetString(profileFlag))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return wrapPreparationError(fmt.Errorf("couldn't get '%s' aws credentials: %w", viper.GetString(profileFlag), err))
|
return wrapPreparationError(fmt.Errorf("couldn't get '%s' aws credentials: %w", viper.GetString(profileFlag), err))
|
||||||
}
|
}
|
||||||
|
@ -117,9 +123,9 @@ func runGeneratePresignedURLCmd(cmd *cobra.Command, _ []string) error {
|
||||||
|
|
||||||
var req *http.Request
|
var req *http.Request
|
||||||
if viper.GetBool(sigV4AFlag) {
|
if viper.GetBool(sigV4AFlag) {
|
||||||
req, err = auth.PresignRequestV4a(creds, reqData, presignData)
|
req, err = auth.PresignRequestV4a(creds, reqData, presignData, log)
|
||||||
} else {
|
} else {
|
||||||
req, err = auth.PresignRequest(cmd.Context(), creds, reqData, presignData)
|
req, err = auth.PresignRequest(ctx, creds, reqData, presignData, log)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return wrapBusinessLogicError(err)
|
return wrapBusinessLogicError(err)
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package modules
|
package modules
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
@ -49,22 +50,25 @@ func initSignCmd() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func runSignCmd(cmd *cobra.Command, _ []string) error {
|
func runSignCmd(cmd *cobra.Command, _ []string) error {
|
||||||
|
ctx, cancel := context.WithTimeout(cmd.Context(), viper.GetDuration(timeoutFlag))
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
var (
|
var (
|
||||||
region string
|
region string
|
||||||
creds aws.Credentials
|
creds aws.Credentials
|
||||||
)
|
)
|
||||||
|
|
||||||
if profile := viper.GetString(profileFlag); profile == "" {
|
if profile := viper.GetString(profileFlag); profile == "" {
|
||||||
cfg, err := config.LoadDefaultConfig(cmd.Context())
|
cfg, err := config.LoadDefaultConfig(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return wrapPreparationError(err)
|
return wrapPreparationError(err)
|
||||||
}
|
}
|
||||||
region = cfg.Region
|
region = cfg.Region
|
||||||
if creds, err = cfg.Credentials.Retrieve(cmd.Context()); err != nil {
|
if creds, err = cfg.Credentials.Retrieve(ctx); err != nil {
|
||||||
return wrapPreparationError(fmt.Errorf("couldn't get default aws credentials: %w", err))
|
return wrapPreparationError(fmt.Errorf("couldn't get default aws credentials: %w", err))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
cfg, err := config.LoadSharedConfigProfile(cmd.Context(), profile)
|
cfg, err := config.LoadSharedConfigProfile(ctx, profile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return wrapPreparationError(fmt.Errorf("couldn't get '%s' aws credentials: %w", profile, err))
|
return wrapPreparationError(fmt.Errorf("couldn't get '%s' aws credentials: %w", profile, err))
|
||||||
}
|
}
|
||||||
|
@ -106,8 +110,8 @@ func runSignCmd(cmd *cobra.Command, _ []string) error {
|
||||||
sigv4a := viper.GetBool(sigV4AFlag)
|
sigv4a := viper.GetBool(sigV4AFlag)
|
||||||
if sigv4a {
|
if sigv4a {
|
||||||
var err error
|
var err error
|
||||||
if signature, err = auth.SignStrV4A(creds, data); err != nil {
|
if signature, err = auth.SignStrV4A(ctx, creds, data); err != nil {
|
||||||
return wrapPreparationError(fmt.Errorf("sign v4a: %w", err))
|
return wrapPreparationError(fmt.Errorf("sign str v4a: %w", err))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
signature = auth.SignStr(creds.SecretAccessKey, service, region, signTime, data)
|
signature = auth.SignStr(creds.SecretAccessKey, service, region, signTime, data)
|
||||||
|
|
Loading…
Reference in a new issue