From 4955009d8a7a0c2cc568c48ff7b65b79229747a0 Mon Sep 17 00:00:00 2001 From: Pierre-Emmanuel Jacquier <15922119+pierre-emmanuelJ@users.noreply.github.com> Date: Thu, 11 Jan 2024 13:56:34 +0000 Subject: [PATCH] Add chain provider Signed-off-by: Pierre-Emmanuel Jacquier <15922119+pierre-emmanuelJ@users.noreply.github.com> --- v3/credentials/chain.go | 57 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 v3/credentials/chain.go diff --git a/v3/credentials/chain.go b/v3/credentials/chain.go new file mode 100644 index 000000000..e15ee0ba8 --- /dev/null +++ b/v3/credentials/chain.go @@ -0,0 +1,57 @@ +package credentials + +import ( + "errors" + "fmt" +) + +var ( + ErrNoValidCredentialProviders = errors.New("no valid credential providers") +) + +// A ChainProvider will search for a provider which returns credentials +// and cache that provider until Retrieve is called again. +type ChainProvider struct { + Providers []Provider + current Provider +} + +// NewChainCredentials returns a pointer to a new Credentials object +// wrapping a chain of providers. +func NewChainCredentials(providers []Provider) *Credentials { + return NewCredentials(&ChainProvider{ + Providers: append([]Provider{}, providers...), + }) +} + +// Retrieve returns the credentials value or error if no provider returned +// without error. +// +// If a provider is found it will be cached and any calls to IsExpired() +// will return the expired state of the cached provider. +func (c *ChainProvider) Retrieve() (Value, error) { + var errs = ErrNoValidCredentialProviders + + for _, p := range c.Providers { + creds, err := p.Retrieve() + if err == nil { + c.current = p + return creds, nil + } + + errs = fmt.Errorf("%v: %w", errs, err) + } + c.current = nil + + return Value{}, fmt.Errorf("chain provider: %w", errs) +} + +// IsExpired will returned the expired state of the currently cached provider +// if there is one. If there is no current provider, true will be returned. +func (c *ChainProvider) IsExpired() bool { + if c.current != nil { + return c.current.IsExpired() + } + + return true +}