117 lines
2.9 KiB
Go
117 lines
2.9 KiB
Go
// This is https://github.com/aws/aws-sdk-go-v2/blob/a2b751d1ba71f59175a41f9cae5f159f1044360f/aws/signer/internal/v4/cache.go
|
|
|
|
package v4
|
|
|
|
import (
|
|
"strings"
|
|
"sync"
|
|
"time"
|
|
|
|
"github.com/aws/aws-sdk-go-v2/aws"
|
|
)
|
|
|
|
func lookupKey(service, region string) string {
|
|
var s strings.Builder
|
|
s.Grow(len(region) + len(service) + 3)
|
|
s.WriteString(region)
|
|
s.WriteRune('/')
|
|
s.WriteString(service)
|
|
return s.String()
|
|
}
|
|
|
|
type derivedKey struct {
|
|
AccessKey string
|
|
Date time.Time
|
|
Credential []byte
|
|
}
|
|
|
|
type derivedKeyCache struct {
|
|
values map[string]derivedKey
|
|
mutex sync.RWMutex
|
|
}
|
|
|
|
func newDerivedKeyCache() derivedKeyCache {
|
|
return derivedKeyCache{
|
|
values: make(map[string]derivedKey),
|
|
}
|
|
}
|
|
|
|
func (s *derivedKeyCache) Get(credentials aws.Credentials, service, region string, signingTime SigningTime) []byte {
|
|
key := lookupKey(service, region)
|
|
s.mutex.RLock()
|
|
if cred, ok := s.get(key, credentials, signingTime.Time); ok {
|
|
s.mutex.RUnlock()
|
|
return cred
|
|
}
|
|
s.mutex.RUnlock()
|
|
|
|
s.mutex.Lock()
|
|
if cred, ok := s.get(key, credentials, signingTime.Time); ok {
|
|
s.mutex.Unlock()
|
|
return cred
|
|
}
|
|
cred := deriveKey(credentials.SecretAccessKey, service, region, signingTime)
|
|
entry := derivedKey{
|
|
AccessKey: credentials.AccessKeyID,
|
|
Date: signingTime.Time,
|
|
Credential: cred,
|
|
}
|
|
s.values[key] = entry
|
|
s.mutex.Unlock()
|
|
|
|
return cred
|
|
}
|
|
|
|
func (s *derivedKeyCache) get(key string, credentials aws.Credentials, signingTime time.Time) ([]byte, bool) {
|
|
cacheEntry, ok := s.retrieveFromCache(key)
|
|
if ok && cacheEntry.AccessKey == credentials.AccessKeyID && isSameDay(signingTime, cacheEntry.Date) {
|
|
return cacheEntry.Credential, true
|
|
}
|
|
return nil, false
|
|
}
|
|
|
|
func (s *derivedKeyCache) retrieveFromCache(key string) (derivedKey, bool) {
|
|
if v, ok := s.values[key]; ok {
|
|
return v, true
|
|
}
|
|
return derivedKey{}, false
|
|
}
|
|
|
|
// SigningKeyDeriver derives a signing key from a set of credentials
|
|
type SigningKeyDeriver struct {
|
|
cache derivedKeyCache
|
|
}
|
|
|
|
// NewSigningKeyDeriver returns a new SigningKeyDeriver
|
|
func NewSigningKeyDeriver() *SigningKeyDeriver {
|
|
return &SigningKeyDeriver{
|
|
cache: newDerivedKeyCache(),
|
|
}
|
|
}
|
|
|
|
// DeriveKey returns a derived signing key from the given credentials to be used with SigV4 signing.
|
|
func (k *SigningKeyDeriver) DeriveKey(credential aws.Credentials, service, region string, signingTime SigningTime) []byte {
|
|
return k.cache.Get(credential, service, region, signingTime)
|
|
}
|
|
|
|
func deriveKey(secret, service, region string, t SigningTime) []byte {
|
|
hmacDate := HMACSHA256([]byte("AWS4"+secret), []byte(t.ShortTimeFormat()))
|
|
hmacRegion := HMACSHA256(hmacDate, []byte(region))
|
|
hmacService := HMACSHA256(hmacRegion, []byte(service))
|
|
return HMACSHA256(hmacService, []byte("aws4_request"))
|
|
}
|
|
|
|
func isSameDay(x, y time.Time) bool {
|
|
xYear, xMonth, xDay := x.Date()
|
|
yYear, yMonth, yDay := y.Date()
|
|
|
|
if xYear != yYear {
|
|
return false
|
|
}
|
|
|
|
if xMonth != yMonth {
|
|
return false
|
|
}
|
|
|
|
return xDay == yDay
|
|
}
|