credentials.go 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. package v4a
  2. import (
  3. "context"
  4. "crypto/ecdsa"
  5. "fmt"
  6. "sync"
  7. "sync/atomic"
  8. "time"
  9. "github.com/aws/aws-sdk-go-v2/aws"
  10. "github.com/aws/aws-sdk-go-v2/internal/sdk"
  11. )
  12. // Credentials is Context, ECDSA, and Optional Session Token that can be used
  13. // to sign requests using SigV4a
  14. type Credentials struct {
  15. Context string
  16. PrivateKey *ecdsa.PrivateKey
  17. SessionToken string
  18. // Time the credentials will expire.
  19. CanExpire bool
  20. Expires time.Time
  21. }
  22. // Expired returns if the credentials have expired.
  23. func (v Credentials) Expired() bool {
  24. if v.CanExpire {
  25. return !v.Expires.After(sdk.NowTime())
  26. }
  27. return false
  28. }
  29. // HasKeys returns if the credentials keys are set.
  30. func (v Credentials) HasKeys() bool {
  31. return len(v.Context) > 0 && v.PrivateKey != nil
  32. }
  33. // SymmetricCredentialAdaptor wraps a SigV4 AccessKey/SecretKey provider and adapts the credentials
  34. // to a ECDSA PrivateKey for signing with SiV4a
  35. type SymmetricCredentialAdaptor struct {
  36. SymmetricProvider aws.CredentialsProvider
  37. asymmetric atomic.Value
  38. m sync.Mutex
  39. }
  40. // Retrieve retrieves symmetric credentials from the underlying provider.
  41. func (s *SymmetricCredentialAdaptor) Retrieve(ctx context.Context) (aws.Credentials, error) {
  42. symCreds, err := s.retrieveFromSymmetricProvider(ctx)
  43. if err != nil {
  44. return aws.Credentials{}, err
  45. }
  46. if asymCreds := s.getCreds(); asymCreds == nil {
  47. return symCreds, nil
  48. }
  49. s.m.Lock()
  50. defer s.m.Unlock()
  51. asymCreds := s.getCreds()
  52. if asymCreds == nil {
  53. return symCreds, nil
  54. }
  55. // if the context does not match the access key id clear it
  56. if asymCreds.Context != symCreds.AccessKeyID {
  57. s.asymmetric.Store((*Credentials)(nil))
  58. }
  59. return symCreds, nil
  60. }
  61. // RetrievePrivateKey returns credentials suitable for SigV4a signing
  62. func (s *SymmetricCredentialAdaptor) RetrievePrivateKey(ctx context.Context) (Credentials, error) {
  63. if asymCreds := s.getCreds(); asymCreds != nil {
  64. return *asymCreds, nil
  65. }
  66. s.m.Lock()
  67. defer s.m.Unlock()
  68. if asymCreds := s.getCreds(); asymCreds != nil {
  69. return *asymCreds, nil
  70. }
  71. symmetricCreds, err := s.retrieveFromSymmetricProvider(ctx)
  72. if err != nil {
  73. return Credentials{}, fmt.Errorf("failed to retrieve symmetric credentials: %v", err)
  74. }
  75. privateKey, err := deriveKeyFromAccessKeyPair(symmetricCreds.AccessKeyID, symmetricCreds.SecretAccessKey)
  76. if err != nil {
  77. return Credentials{}, fmt.Errorf("failed to derive assymetric key from credentials")
  78. }
  79. creds := Credentials{
  80. Context: symmetricCreds.AccessKeyID,
  81. PrivateKey: privateKey,
  82. SessionToken: symmetricCreds.SessionToken,
  83. CanExpire: symmetricCreds.CanExpire,
  84. Expires: symmetricCreds.Expires,
  85. }
  86. s.asymmetric.Store(&creds)
  87. return creds, nil
  88. }
  89. func (s *SymmetricCredentialAdaptor) getCreds() *Credentials {
  90. v := s.asymmetric.Load()
  91. if v == nil {
  92. return nil
  93. }
  94. c := v.(*Credentials)
  95. if c != nil && c.HasKeys() && !c.Expired() {
  96. return c
  97. }
  98. return nil
  99. }
  100. func (s *SymmetricCredentialAdaptor) retrieveFromSymmetricProvider(ctx context.Context) (aws.Credentials, error) {
  101. credentials, err := s.SymmetricProvider.Retrieve(ctx)
  102. if err != nil {
  103. return aws.Credentials{}, err
  104. }
  105. return credentials, nil
  106. }
  107. // CredentialsProvider is the interface for a provider to retrieve credentials
  108. // to sign requests with.
  109. type CredentialsProvider interface {
  110. RetrievePrivateKey(context.Context) (Credentials, error)
  111. }