| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141 |
- package v4a
- import (
- "context"
- "crypto/ecdsa"
- "fmt"
- "sync"
- "sync/atomic"
- "time"
- "github.com/aws/aws-sdk-go-v2/aws"
- "github.com/aws/aws-sdk-go-v2/internal/sdk"
- )
- // Credentials is Context, ECDSA, and Optional Session Token that can be used
- // to sign requests using SigV4a
- type Credentials struct {
- Context string
- PrivateKey *ecdsa.PrivateKey
- SessionToken string
- // Time the credentials will expire.
- CanExpire bool
- Expires time.Time
- }
- // Expired returns if the credentials have expired.
- func (v Credentials) Expired() bool {
- if v.CanExpire {
- return !v.Expires.After(sdk.NowTime())
- }
- return false
- }
- // HasKeys returns if the credentials keys are set.
- func (v Credentials) HasKeys() bool {
- return len(v.Context) > 0 && v.PrivateKey != nil
- }
- // SymmetricCredentialAdaptor wraps a SigV4 AccessKey/SecretKey provider and adapts the credentials
- // to a ECDSA PrivateKey for signing with SiV4a
- type SymmetricCredentialAdaptor struct {
- SymmetricProvider aws.CredentialsProvider
- asymmetric atomic.Value
- m sync.Mutex
- }
- // Retrieve retrieves symmetric credentials from the underlying provider.
- func (s *SymmetricCredentialAdaptor) Retrieve(ctx context.Context) (aws.Credentials, error) {
- symCreds, err := s.retrieveFromSymmetricProvider(ctx)
- if err != nil {
- return aws.Credentials{}, err
- }
- if asymCreds := s.getCreds(); asymCreds == nil {
- return symCreds, nil
- }
- s.m.Lock()
- defer s.m.Unlock()
- asymCreds := s.getCreds()
- if asymCreds == nil {
- return symCreds, nil
- }
- // if the context does not match the access key id clear it
- if asymCreds.Context != symCreds.AccessKeyID {
- s.asymmetric.Store((*Credentials)(nil))
- }
- return symCreds, nil
- }
- // RetrievePrivateKey returns credentials suitable for SigV4a signing
- func (s *SymmetricCredentialAdaptor) RetrievePrivateKey(ctx context.Context) (Credentials, error) {
- if asymCreds := s.getCreds(); asymCreds != nil {
- return *asymCreds, nil
- }
- s.m.Lock()
- defer s.m.Unlock()
- if asymCreds := s.getCreds(); asymCreds != nil {
- return *asymCreds, nil
- }
- symmetricCreds, err := s.retrieveFromSymmetricProvider(ctx)
- if err != nil {
- return Credentials{}, fmt.Errorf("failed to retrieve symmetric credentials: %v", err)
- }
- privateKey, err := deriveKeyFromAccessKeyPair(symmetricCreds.AccessKeyID, symmetricCreds.SecretAccessKey)
- if err != nil {
- return Credentials{}, fmt.Errorf("failed to derive assymetric key from credentials")
- }
- creds := Credentials{
- Context: symmetricCreds.AccessKeyID,
- PrivateKey: privateKey,
- SessionToken: symmetricCreds.SessionToken,
- CanExpire: symmetricCreds.CanExpire,
- Expires: symmetricCreds.Expires,
- }
- s.asymmetric.Store(&creds)
- return creds, nil
- }
- func (s *SymmetricCredentialAdaptor) getCreds() *Credentials {
- v := s.asymmetric.Load()
- if v == nil {
- return nil
- }
- c := v.(*Credentials)
- if c != nil && c.HasKeys() && !c.Expired() {
- return c
- }
- return nil
- }
- func (s *SymmetricCredentialAdaptor) retrieveFromSymmetricProvider(ctx context.Context) (aws.Credentials, error) {
- credentials, err := s.SymmetricProvider.Retrieve(ctx)
- if err != nil {
- return aws.Credentials{}, err
- }
- return credentials, nil
- }
- // CredentialsProvider is the interface for a provider to retrieve credentials
- // to sign requests with.
- type CredentialsProvider interface {
- RetrievePrivateKey(context.Context) (Credentials, error)
- }
|