aboutsummaryrefslogtreecommitdiffstats
path: root/vendor/github.com/aws/aws-sdk-go-v2/internal/v4a/presign_middleware.go
blob: 951fc415d5274a2b15f52c1f1eee8849233e8b87 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
package v4a

import (
	"context"
	"fmt"
	"net/http"
	"time"

	awsmiddleware "github.com/aws/aws-sdk-go-v2/aws/middleware"
	v4 "github.com/aws/aws-sdk-go-v2/aws/signer/v4"
	"github.com/aws/aws-sdk-go-v2/internal/sdk"
	"github.com/aws/smithy-go/middleware"
	smithyHTTP "github.com/aws/smithy-go/transport/http"
)

// HTTPPresigner is an interface to a SigV4a signer that can sign create a
// presigned URL for a HTTP requests.
type HTTPPresigner interface {
	PresignHTTP(
		ctx context.Context, credentials Credentials, r *http.Request,
		payloadHash string, service string, regionSet []string, signingTime time.Time,
		optFns ...func(*SignerOptions),
	) (url string, signedHeader http.Header, err error)
}

// PresignHTTPRequestMiddlewareOptions is the options for the PresignHTTPRequestMiddleware middleware.
type PresignHTTPRequestMiddlewareOptions struct {
	CredentialsProvider CredentialsProvider
	Presigner           HTTPPresigner
	LogSigning          bool
}

// PresignHTTPRequestMiddleware provides the Finalize middleware for creating a
// presigned URL for an HTTP request.
//
// Will short circuit the middleware stack and not forward onto the next
// Finalize handler.
type PresignHTTPRequestMiddleware struct {
	credentialsProvider CredentialsProvider
	presigner           HTTPPresigner
	logSigning          bool
}

// NewPresignHTTPRequestMiddleware returns a new PresignHTTPRequestMiddleware
// initialized with the presigner.
func NewPresignHTTPRequestMiddleware(options PresignHTTPRequestMiddlewareOptions) *PresignHTTPRequestMiddleware {
	return &PresignHTTPRequestMiddleware{
		credentialsProvider: options.CredentialsProvider,
		presigner:           options.Presigner,
		logSigning:          options.LogSigning,
	}
}

// ID provides the middleware ID.
func (*PresignHTTPRequestMiddleware) ID() string { return "PresignHTTPRequest" }

// HandleFinalize will take the provided input and create a presigned url for
// the http request using the SigV4 presign authentication scheme.
func (s *PresignHTTPRequestMiddleware) HandleFinalize(
	ctx context.Context, in middleware.FinalizeInput, next middleware.FinalizeHandler,
) (
	out middleware.FinalizeOutput, metadata middleware.Metadata, err error,
) {
	req, ok := in.Request.(*smithyHTTP.Request)
	if !ok {
		return out, metadata, &SigningError{
			Err: fmt.Errorf("unexpected request middleware type %T", in.Request),
		}
	}

	httpReq := req.Build(ctx)
	if !hasCredentialProvider(s.credentialsProvider) {
		out.Result = &v4.PresignedHTTPRequest{
			URL:          httpReq.URL.String(),
			Method:       httpReq.Method,
			SignedHeader: http.Header{},
		}

		return out, metadata, nil
	}

	signingName := awsmiddleware.GetSigningName(ctx)
	signingRegion := awsmiddleware.GetSigningRegion(ctx)
	payloadHash := v4.GetPayloadHash(ctx)
	if len(payloadHash) == 0 {
		return out, metadata, &SigningError{
			Err: fmt.Errorf("computed payload hash missing from context"),
		}
	}

	credentials, err := s.credentialsProvider.RetrievePrivateKey(ctx)
	if err != nil {
		return out, metadata, &SigningError{
			Err: fmt.Errorf("failed to retrieve credentials: %w", err),
		}
	}

	u, h, err := s.presigner.PresignHTTP(ctx, credentials,
		httpReq, payloadHash, signingName, []string{signingRegion}, sdk.NowTime(),
		func(o *SignerOptions) {
			o.Logger = middleware.GetLogger(ctx)
			o.LogSigning = s.logSigning
		})
	if err != nil {
		return out, metadata, &SigningError{
			Err: fmt.Errorf("failed to sign http request, %w", err),
		}
	}

	out.Result = &v4.PresignedHTTPRequest{
		URL:          u,
		Method:       httpReq.Method,
		SignedHeader: h,
	}

	return out, metadata, nil
}