[#505] authmate: Add flag for headers in generate-presigned-url cmd

Signed-off-by: Marina Biryukova <m.biryukova@yadro.com>
This commit is contained in:
Marina Biryukova 2024-10-29 16:26:01 +03:00 committed by Alexey Vanin
parent 539dab8680
commit 979d85b046
2 changed files with 33 additions and 2 deletions

View file

@ -23,6 +23,7 @@ type PresignData struct {
Region string Region string
Lifetime time.Duration Lifetime time.Duration
SignTime time.Time SignTime time.Time
Headers map[string]string
} }
// PresignRequest forms pre-signed request to access objects without aws credentials. // PresignRequest forms pre-signed request to access objects without aws credentials.
@ -34,7 +35,10 @@ func PresignRequest(creds *credentials.Credentials, reqData RequestData, presign
} }
req.Header.Set(AmzDate, presignData.SignTime.Format("20060102T150405Z")) req.Header.Set(AmzDate, presignData.SignTime.Format("20060102T150405Z"))
req.Header.Set(ContentTypeHdr, "text/plain")
for k, v := range presignData.Headers {
req.Header.Set(k, v)
}
signer := v4.NewSigner(creds) signer := v4.NewSigner(creds)
signer.DisableURIPathEscaping = true signer.DisableURIPathEscaping = true

View file

@ -4,6 +4,7 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"os" "os"
"strings"
"time" "time"
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/auth" "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/auth"
@ -21,7 +22,7 @@ var generatePresignedURLCmd = &cobra.Command{
You provide profile to load using --profile flag or explicitly provide credentials and region using You provide profile to load using --profile flag or explicitly provide credentials and region using
--aws-access-key-id, --aws-secret-access-key, --region. --aws-access-key-id, --aws-secret-access-key, --region.
Note to override credentials you must provide both access key and secret key.`, Note to override credentials you must provide both access key and secret key.`,
Example: `frostfs-s3-authmate generate-presigned-url --method put --bucket my-bucket --object my-object --endpoint http://localhost:8084 --lifetime 12h --region ru --aws-access-key-id ETaA2CadPcA7bAkLsML2PbTudXY8uRt2PDjCCwkvRv9s0FDCxWDXYc1SA1vKv8KbyCNsLY2AmAjJ92Vz5rgvsFCy --aws-secret-access-key c2d65ef2980f03f4f495bdebedeeae760496697880d61d106bb9a4e5cd2e0607`, Example: `frostfs-s3-authmate generate-presigned-url --method put --bucket my-bucket --object my-object --endpoint http://localhost:8084 --lifetime 12h --region ru --aws-access-key-id ETaA2CadPcA7bAkLsML2PbTudXY8uRt2PDjCCwkvRv9s0FDCxWDXYc1SA1vKv8KbyCNsLY2AmAjJ92Vz5rgvsFCy --aws-secret-access-key c2d65ef2980f03f4f495bdebedeeae760496697880d61d106bb9a4e5cd2e0607 --header 'Content-Type: text/plain'`,
RunE: runGeneratePresignedURLCmd, RunE: runGeneratePresignedURLCmd,
} }
@ -36,6 +37,7 @@ const (
regionFlag = "region" regionFlag = "region"
awsAccessKeyIDFlag = "aws-access-key-id" awsAccessKeyIDFlag = "aws-access-key-id"
awsSecretAccessKeyFlag = "aws-secret-access-key" awsSecretAccessKeyFlag = "aws-secret-access-key"
headerFlag = "header"
) )
func initGeneratePresignedURLCmd() { func initGeneratePresignedURLCmd() {
@ -48,6 +50,7 @@ func initGeneratePresignedURLCmd() {
generatePresignedURLCmd.Flags().String(regionFlag, "", "AWS region to use in signature (default is taken from ~/.aws/config)") generatePresignedURLCmd.Flags().String(regionFlag, "", "AWS region to use in signature (default is taken from ~/.aws/config)")
generatePresignedURLCmd.Flags().String(awsAccessKeyIDFlag, "", "AWS access key id to sign the URL (default is taken from ~/.aws/credentials)") generatePresignedURLCmd.Flags().String(awsAccessKeyIDFlag, "", "AWS access key id to sign the URL (default is taken from ~/.aws/credentials)")
generatePresignedURLCmd.Flags().String(awsSecretAccessKeyFlag, "", "AWS secret access key to sign the URL (default is taken from ~/.aws/credentials)") generatePresignedURLCmd.Flags().String(awsSecretAccessKeyFlag, "", "AWS secret access key to sign the URL (default is taken from ~/.aws/credentials)")
generatePresignedURLCmd.Flags().StringSlice(headerFlag, nil, "Header in form of 'Key: value' to use in presigned URL (use flags repeatedly for multiple headers or separate them by comma)")
_ = generatePresignedURLCmd.MarkFlagRequired(endpointFlag) _ = generatePresignedURLCmd.MarkFlagRequired(endpointFlag)
_ = generatePresignedURLCmd.MarkFlagRequired(bucketFlag) _ = generatePresignedURLCmd.MarkFlagRequired(bucketFlag)
@ -92,6 +95,12 @@ func runGeneratePresignedURLCmd(*cobra.Command, []string) error {
SignTime: time.Now().UTC(), SignTime: time.Now().UTC(),
} }
headers, err := parseHeaders()
if err != nil {
return wrapPreparationError(fmt.Errorf("failed to parse headers: %s", err))
}
presignData.Headers = headers
req, err := auth.PresignRequest(sess.Config.Credentials, reqData, presignData) req, err := auth.PresignRequest(sess.Config.Credentials, reqData, presignData)
if err != nil { if err != nil {
return wrapBusinessLogicError(err) return wrapBusinessLogicError(err)
@ -110,3 +119,21 @@ func runGeneratePresignedURLCmd(*cobra.Command, []string) error {
} }
return nil return nil
} }
func parseHeaders() (map[string]string, error) {
headers := viper.GetStringSlice(headerFlag)
if len(headers) == 0 {
return nil, nil
}
result := make(map[string]string, len(headers))
for _, header := range headers {
k, v, found := strings.Cut(header, ":")
if !found {
return nil, fmt.Errorf("invalid header format: %s", header)
}
result[strings.Trim(k, " ")] = strings.Trim(v, " ")
}
return result, nil
}