| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246 |
- // Package credentials provides credential retrieval and management
- //
- // The Credentials is the primary method of getting access to and managing
- // credentials Values. Using dependency injection retrieval of the credential
- // values is handled by a object which satisfies the Provider interface.
- //
- // By default the Credentials.Get() will cache the successful result of a
- // Provider's Retrieve() until Provider.IsExpired() returns true. At which
- // point Credentials will call Provider's Retrieve() to get new credential Value.
- //
- // The Provider is responsible for determining when credentials Value have expired.
- // It is also important to note that Credentials will always call Retrieve the
- // first time Credentials.Get() is called.
- //
- // Example of using the environment variable credentials.
- //
- // creds := credentials.NewEnvCredentials()
- //
- // // Retrieve the credentials value
- // credValue, err := creds.Get()
- // if err != nil {
- // // handle error
- // }
- //
- // Example of forcing credentials to expire and be refreshed on the next Get().
- // This may be helpful to proactively expire credentials and refresh them sooner
- // than they would naturally expire on their own.
- //
- // creds := credentials.NewCredentials(&ec2rolecreds.EC2RoleProvider{})
- // creds.Expire()
- // credsValue, err := creds.Get()
- // // New credentials will be retrieved instead of from cache.
- //
- //
- // Custom Provider
- //
- // Each Provider built into this package also provides a helper method to generate
- // a Credentials pointer setup with the provider. To use a custom Provider just
- // create a type which satisfies the Provider interface and pass it to the
- // NewCredentials method.
- //
- // type MyProvider struct{}
- // func (m *MyProvider) Retrieve() (Value, error) {...}
- // func (m *MyProvider) IsExpired() bool {...}
- //
- // creds := credentials.NewCredentials(&MyProvider{})
- // credValue, err := creds.Get()
- //
- package credentials
- import (
- "sync"
- "time"
- )
- // AnonymousCredentials is an empty Credential object that can be used as
- // dummy placeholder credentials for requests that do not need signed.
- //
- // This Credentials can be used to configure a service to not sign requests
- // when making service API calls. For example, when accessing public
- // s3 buckets.
- //
- // svc := s3.New(session.Must(session.NewSession(&aws.Config{
- // Credentials: credentials.AnonymousCredentials,
- // })))
- // // Access public S3 buckets.
- //
- // @readonly
- var AnonymousCredentials = NewStaticCredentials("", "", "")
- // A Value is the AWS credentials value for individual credential fields.
- type Value struct {
- // AWS Access key ID
- AccessKeyID string
- // AWS Secret Access Key
- SecretAccessKey string
- // AWS Session Token
- SessionToken string
- // Provider used to get credentials
- ProviderName string
- }
- // A Provider is the interface for any component which will provide credentials
- // Value. A provider is required to manage its own Expired state, and what to
- // be expired means.
- //
- // The Provider should not need to implement its own mutexes, because
- // that will be managed by Credentials.
- type Provider interface {
- // Retrieve returns nil if it successfully retrieved the value.
- // Error is returned if the value were not obtainable, or empty.
- Retrieve() (Value, error)
- // IsExpired returns if the credentials are no longer valid, and need
- // to be retrieved.
- IsExpired() bool
- }
- // An ErrorProvider is a stub credentials provider that always returns an error
- // this is used by the SDK when construction a known provider is not possible
- // due to an error.
- type ErrorProvider struct {
- // The error to be returned from Retrieve
- Err error
- // The provider name to set on the Retrieved returned Value
- ProviderName string
- }
- // Retrieve will always return the error that the ErrorProvider was created with.
- func (p ErrorProvider) Retrieve() (Value, error) {
- return Value{ProviderName: p.ProviderName}, p.Err
- }
- // IsExpired will always return not expired.
- func (p ErrorProvider) IsExpired() bool {
- return false
- }
- // A Expiry provides shared expiration logic to be used by credentials
- // providers to implement expiry functionality.
- //
- // The best method to use this struct is as an anonymous field within the
- // provider's struct.
- //
- // Example:
- // type EC2RoleProvider struct {
- // Expiry
- // ...
- // }
- type Expiry struct {
- // The date/time when to expire on
- expiration time.Time
- // If set will be used by IsExpired to determine the current time.
- // Defaults to time.Now if CurrentTime is not set. Available for testing
- // to be able to mock out the current time.
- CurrentTime func() time.Time
- }
- // SetExpiration sets the expiration IsExpired will check when called.
- //
- // If window is greater than 0 the expiration time will be reduced by the
- // window value.
- //
- // Using a window is helpful to trigger credentials to expire sooner than
- // the expiration time given to ensure no requests are made with expired
- // tokens.
- func (e *Expiry) SetExpiration(expiration time.Time, window time.Duration) {
- e.expiration = expiration
- if window > 0 {
- e.expiration = e.expiration.Add(-window)
- }
- }
- // IsExpired returns if the credentials are expired.
- func (e *Expiry) IsExpired() bool {
- if e.CurrentTime == nil {
- e.CurrentTime = time.Now
- }
- return e.expiration.Before(e.CurrentTime())
- }
- // A Credentials provides synchronous safe retrieval of AWS credentials Value.
- // Credentials will cache the credentials value until they expire. Once the value
- // expires the next Get will attempt to retrieve valid credentials.
- //
- // Credentials is safe to use across multiple goroutines and will manage the
- // synchronous state so the Providers do not need to implement their own
- // synchronization.
- //
- // The first Credentials.Get() will always call Provider.Retrieve() to get the
- // first instance of the credentials Value. All calls to Get() after that
- // will return the cached credentials Value until IsExpired() returns true.
- type Credentials struct {
- creds Value
- forceRefresh bool
- m sync.Mutex
- provider Provider
- }
- // NewCredentials returns a pointer to a new Credentials with the provider set.
- func NewCredentials(provider Provider) *Credentials {
- return &Credentials{
- provider: provider,
- forceRefresh: true,
- }
- }
- // Get returns the credentials value, or error if the credentials Value failed
- // to be retrieved.
- //
- // Will return the cached credentials Value if it has not expired. If the
- // credentials Value has expired the Provider's Retrieve() will be called
- // to refresh the credentials.
- //
- // If Credentials.Expire() was called the credentials Value will be force
- // expired, and the next call to Get() will cause them to be refreshed.
- func (c *Credentials) Get() (Value, error) {
- c.m.Lock()
- defer c.m.Unlock()
- if c.isExpired() {
- creds, err := c.provider.Retrieve()
- if err != nil {
- return Value{}, err
- }
- c.creds = creds
- c.forceRefresh = false
- }
- return c.creds, nil
- }
- // Expire expires the credentials and forces them to be retrieved on the
- // next call to Get().
- //
- // This will override the Provider's expired state, and force Credentials
- // to call the Provider's Retrieve().
- func (c *Credentials) Expire() {
- c.m.Lock()
- defer c.m.Unlock()
- c.forceRefresh = true
- }
- // IsExpired returns if the credentials are no longer valid, and need
- // to be retrieved.
- //
- // If the Credentials were forced to be expired with Expire() this will
- // reflect that override.
- func (c *Credentials) IsExpired() bool {
- c.m.Lock()
- defer c.m.Unlock()
- return c.isExpired()
- }
- // isExpired helper method wrapping the definition of expired credentials.
- func (c *Credentials) isExpired() bool {
- return c.forceRefresh || c.provider.IsExpired()
- }
|