presign_middleware.go 3.5 KB

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