src

Go monorepo.
git clone git://code.dwrz.net/src
Log | Files | Refs

presign_middleware.go (3634B)


      1 package v4a
      2 
      3 import (
      4 	"context"
      5 	"fmt"
      6 	"net/http"
      7 	"time"
      8 
      9 	awsmiddleware "github.com/aws/aws-sdk-go-v2/aws/middleware"
     10 	v4 "github.com/aws/aws-sdk-go-v2/aws/signer/v4"
     11 	"github.com/aws/aws-sdk-go-v2/internal/sdk"
     12 	"github.com/aws/smithy-go/middleware"
     13 	smithyHTTP "github.com/aws/smithy-go/transport/http"
     14 )
     15 
     16 // HTTPPresigner is an interface to a SigV4a signer that can sign create a
     17 // presigned URL for a HTTP requests.
     18 type HTTPPresigner interface {
     19 	PresignHTTP(
     20 		ctx context.Context, credentials Credentials, r *http.Request,
     21 		payloadHash string, service string, regionSet []string, signingTime time.Time,
     22 		optFns ...func(*SignerOptions),
     23 	) (url string, signedHeader http.Header, err error)
     24 }
     25 
     26 // PresignHTTPRequestMiddlewareOptions is the options for the PresignHTTPRequestMiddleware middleware.
     27 type PresignHTTPRequestMiddlewareOptions struct {
     28 	CredentialsProvider CredentialsProvider
     29 	Presigner           HTTPPresigner
     30 	LogSigning          bool
     31 }
     32 
     33 // PresignHTTPRequestMiddleware provides the Finalize middleware for creating a
     34 // presigned URL for an HTTP request.
     35 //
     36 // Will short circuit the middleware stack and not forward onto the next
     37 // Finalize handler.
     38 type PresignHTTPRequestMiddleware struct {
     39 	credentialsProvider CredentialsProvider
     40 	presigner           HTTPPresigner
     41 	logSigning          bool
     42 }
     43 
     44 // NewPresignHTTPRequestMiddleware returns a new PresignHTTPRequestMiddleware
     45 // initialized with the presigner.
     46 func NewPresignHTTPRequestMiddleware(options PresignHTTPRequestMiddlewareOptions) *PresignHTTPRequestMiddleware {
     47 	return &PresignHTTPRequestMiddleware{
     48 		credentialsProvider: options.CredentialsProvider,
     49 		presigner:           options.Presigner,
     50 		logSigning:          options.LogSigning,
     51 	}
     52 }
     53 
     54 // ID provides the middleware ID.
     55 func (*PresignHTTPRequestMiddleware) ID() string { return "PresignHTTPRequest" }
     56 
     57 // HandleFinalize will take the provided input and create a presigned url for
     58 // the http request using the SigV4 presign authentication scheme.
     59 func (s *PresignHTTPRequestMiddleware) HandleFinalize(
     60 	ctx context.Context, in middleware.FinalizeInput, next middleware.FinalizeHandler,
     61 ) (
     62 	out middleware.FinalizeOutput, metadata middleware.Metadata, err error,
     63 ) {
     64 	req, ok := in.Request.(*smithyHTTP.Request)
     65 	if !ok {
     66 		return out, metadata, &SigningError{
     67 			Err: fmt.Errorf("unexpected request middleware type %T", in.Request),
     68 		}
     69 	}
     70 
     71 	httpReq := req.Build(ctx)
     72 	if !hasCredentialProvider(s.credentialsProvider) {
     73 		out.Result = &v4.PresignedHTTPRequest{
     74 			URL:          httpReq.URL.String(),
     75 			Method:       httpReq.Method,
     76 			SignedHeader: http.Header{},
     77 		}
     78 
     79 		return out, metadata, nil
     80 	}
     81 
     82 	signingName := awsmiddleware.GetSigningName(ctx)
     83 	signingRegion := awsmiddleware.GetSigningRegion(ctx)
     84 	payloadHash := v4.GetPayloadHash(ctx)
     85 	if len(payloadHash) == 0 {
     86 		return out, metadata, &SigningError{
     87 			Err: fmt.Errorf("computed payload hash missing from context"),
     88 		}
     89 	}
     90 
     91 	credentials, err := s.credentialsProvider.RetrievePrivateKey(ctx)
     92 	if err != nil {
     93 		return out, metadata, &SigningError{
     94 			Err: fmt.Errorf("failed to retrieve credentials: %w", err),
     95 		}
     96 	}
     97 
     98 	u, h, err := s.presigner.PresignHTTP(ctx, credentials,
     99 		httpReq, payloadHash, signingName, []string{signingRegion}, sdk.NowTime(),
    100 		func(o *SignerOptions) {
    101 			o.Logger = middleware.GetLogger(ctx)
    102 			o.LogSigning = s.logSigning
    103 		})
    104 	if err != nil {
    105 		return out, metadata, &SigningError{
    106 			Err: fmt.Errorf("failed to sign http request, %w", err),
    107 		}
    108 	}
    109 
    110 	out.Result = &v4.PresignedHTTPRequest{
    111 		URL:          u,
    112 		Method:       httpReq.Method,
    113 		SignedHeader: h,
    114 	}
    115 
    116 	return out, metadata, nil
    117 }