/
signer_wrapper.go
227 lines (193 loc) · 7.5 KB
/
signer_wrapper.go
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
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
package customizations
import (
"context"
"fmt"
"strings"
"github.com/aws/aws-sdk-go-v2/aws"
v4 "github.com/aws/aws-sdk-go-v2/aws/signer/v4"
"github.com/aws/aws-sdk-go-v2/internal/v4a"
"github.com/aws/smithy-go/middleware"
)
type signerVersionKey struct{}
// GetSignerVersion retrieves the signer version to use for signing
//
// Scoped to stack values. Use github.com/aws/smithy-go/middleware#ClearStackValues
// to clear all stack values.
func GetSignerVersion(ctx context.Context) (v string) {
v, _ = middleware.GetStackValue(ctx, signerVersionKey{}).(string)
return v
}
// SetSignerVersion sets the signer version to be used for signing the request
//
// Scoped to stack values. Use github.com/aws/smithy-go/middleware#ClearStackValues
// to clear all stack values.
func SetSignerVersion(ctx context.Context, version string) context.Context {
return middleware.WithStackValue(ctx, signerVersionKey{}, version)
}
// SignHTTPRequestMiddlewareOptions is the configuration options for the SignHTTPRequestMiddleware middleware.
type SignHTTPRequestMiddlewareOptions struct {
// credential provider
CredentialsProvider aws.CredentialsProvider
// log signing
LogSigning bool
// v4 signer
V4Signer v4.HTTPSigner
//v4a signer
V4aSigner v4a.HTTPSigner
}
// NewSignHTTPRequestMiddleware constructs a SignHTTPRequestMiddleware using the given Signer for signing requests
func NewSignHTTPRequestMiddleware(options SignHTTPRequestMiddlewareOptions) *SignHTTPRequestMiddleware {
return &SignHTTPRequestMiddleware{
credentialsProvider: options.CredentialsProvider,
v4Signer: options.V4Signer,
v4aSigner: options.V4aSigner,
logSigning: options.LogSigning,
}
}
// SignHTTPRequestMiddleware is a `FinalizeMiddleware` implementation to select HTTP Signing method
type SignHTTPRequestMiddleware struct {
// credential provider
credentialsProvider aws.CredentialsProvider
// log signing
logSigning bool
// v4 signer
v4Signer v4.HTTPSigner
//v4a signer
v4aSigner v4a.HTTPSigner
}
// ID is the SignHTTPRequestMiddleware identifier
func (s *SignHTTPRequestMiddleware) ID() string {
return "Signing"
}
// HandleFinalize will take the provided input and handle signing for either
// SigV4 or SigV4A as called for.
func (s *SignHTTPRequestMiddleware) HandleFinalize(ctx context.Context, in middleware.FinalizeInput, next middleware.FinalizeHandler) (
out middleware.FinalizeOutput, metadata middleware.Metadata, err error,
) {
sv := GetSignerVersion(ctx)
if strings.EqualFold(sv, v4.Version) {
mw := v4.NewSignHTTPRequestMiddleware(v4.SignHTTPRequestMiddlewareOptions{
CredentialsProvider: s.credentialsProvider,
Signer: s.v4Signer,
LogSigning: s.logSigning,
})
return mw.HandleFinalize(ctx, in, next)
} else if strings.EqualFold(sv, v4a.Version) {
v4aCredentialProvider, ok := s.credentialsProvider.(v4a.CredentialsProvider)
if !ok {
return out, metadata, fmt.Errorf("invalid credential-provider provided for sigV4a Signer")
}
mw := v4a.NewSignHTTPRequestMiddleware(v4a.SignHTTPRequestMiddlewareOptions{
Credentials: v4aCredentialProvider,
Signer: s.v4aSigner,
LogSigning: s.logSigning,
})
return mw.HandleFinalize(ctx, in, next)
}
return next.HandleFinalize(ctx, in)
}
// RegisterSigningMiddleware registers the wrapper signing middleware to the stack. If a signing middleware is already
// present, this provided middleware will be swapped. Otherwise the middleware will be added at the tail of the
// finalize step.
func RegisterSigningMiddleware(stack *middleware.Stack, signingMiddleware *SignHTTPRequestMiddleware) (err error) {
const signedID = "Signing"
_, present := stack.Finalize.Get(signedID)
if present {
_, err = stack.Finalize.Swap(signedID, signingMiddleware)
} else {
err = stack.Finalize.Add(signingMiddleware, middleware.After)
}
return err
}
// PresignHTTPRequestMiddlewareOptions is the options for the PresignHTTPRequestMiddleware middleware.
type PresignHTTPRequestMiddlewareOptions struct {
CredentialsProvider aws.CredentialsProvider
ExpressCredentials S3ExpressCredentialsProvider
V4Presigner v4.HTTPPresigner
V4aPresigner v4a.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 {
// cred provider and signer for sigv4
credentialsProvider aws.CredentialsProvider
// s3Express credentials
expressCredentials S3ExpressCredentialsProvider
// sigV4 signer
v4Signer v4.HTTPPresigner
// sigV4a signer
v4aSigner v4a.HTTPPresigner
// log signing
logSigning bool
}
// NewPresignHTTPRequestMiddleware constructs a PresignHTTPRequestMiddleware using the given Signer for signing requests
func NewPresignHTTPRequestMiddleware(options PresignHTTPRequestMiddlewareOptions) *PresignHTTPRequestMiddleware {
return &PresignHTTPRequestMiddleware{
credentialsProvider: options.CredentialsProvider,
expressCredentials: options.ExpressCredentials,
v4Signer: options.V4Presigner,
v4aSigner: options.V4aPresigner,
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 or SigV4a presign authentication scheme.
//
// Since the signed request is not a valid HTTP request
func (p *PresignHTTPRequestMiddleware) HandleFinalize(
ctx context.Context, in middleware.FinalizeInput, next middleware.FinalizeHandler,
) (
out middleware.FinalizeOutput, metadata middleware.Metadata, err error,
) {
// fetch signer type from context
signerVersion := GetSignerVersion(ctx)
switch signerVersion {
case "aws.auth#sigv4a":
mw := v4a.NewPresignHTTPRequestMiddleware(v4a.PresignHTTPRequestMiddlewareOptions{
CredentialsProvider: &v4a.SymmetricCredentialAdaptor{
SymmetricProvider: p.credentialsProvider,
},
Presigner: p.v4aSigner,
LogSigning: p.logSigning,
})
return mw.HandleFinalize(ctx, in, next)
case "aws.auth#sigv4":
mw := v4.NewPresignHTTPRequestMiddleware(v4.PresignHTTPRequestMiddlewareOptions{
CredentialsProvider: p.credentialsProvider,
Presigner: p.v4Signer,
LogSigning: p.logSigning,
})
return mw.HandleFinalize(ctx, in, next)
case s3ExpressSignerVersion:
mw := v4.NewPresignHTTPRequestMiddleware(v4.PresignHTTPRequestMiddlewareOptions{
CredentialsProvider: &s3ExpressCredentialsAdapter{
provider: p.expressCredentials,
bucket: GetBucket(ctx),
},
Presigner: &s3ExpressPresignerAdapter{v4: p.v4Signer},
LogSigning: p.logSigning,
})
return mw.HandleFinalize(ctx, in, next)
default:
return out, metadata, fmt.Errorf("unsupported signer type \"%s\"", signerVersion)
}
}
// RegisterPreSigningMiddleware registers the wrapper pre-signing middleware to the stack. If a pre-signing middleware is already
// present, this provided middleware will be swapped. Otherwise the middleware will be added at the tail of the
// finalize step.
func RegisterPreSigningMiddleware(stack *middleware.Stack, signingMiddleware *PresignHTTPRequestMiddleware) (err error) {
const signedID = "PresignHTTPRequest"
_, present := stack.Finalize.Get(signedID)
if present {
_, err = stack.Finalize.Swap(signedID, signingMiddleware)
} else {
err = stack.Finalize.Add(signingMiddleware, middleware.After)
}
return err
}