1package auth
2
3import (
4	"github.com/hashicorp/terraform/svchost"
5)
6
7// CachingCredentialsSource creates a new credentials source that wraps another
8// and caches its results in memory, on a per-hostname basis.
9//
10// No means is provided for expiration of cached credentials, so a caching
11// credentials source should have a limited lifetime (one Terraform operation,
12// for example) to ensure that time-limited credentials don't expire before
13// their cache entries do.
14func CachingCredentialsSource(source CredentialsSource) CredentialsSource {
15	return &cachingCredentialsSource{
16		source: source,
17		cache:  map[svchost.Hostname]HostCredentials{},
18	}
19}
20
21type cachingCredentialsSource struct {
22	source CredentialsSource
23	cache  map[svchost.Hostname]HostCredentials
24}
25
26// ForHost passes the given hostname on to the wrapped credentials source and
27// caches the result to return for future requests with the same hostname.
28//
29// Both credentials and non-credentials (nil) responses are cached.
30//
31// No cache entry is created if the wrapped source returns an error, to allow
32// the caller to retry the failing operation.
33func (s *cachingCredentialsSource) ForHost(host svchost.Hostname) (HostCredentials, error) {
34	if cache, cached := s.cache[host]; cached {
35		return cache, nil
36	}
37
38	result, err := s.source.ForHost(host)
39	if err != nil {
40		return result, err
41	}
42
43	s.cache[host] = result
44	return result, nil
45}
46