credentials.go 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. /*
  2. * MinIO Go Library for Amazon S3 Compatible Cloud Storage
  3. * Copyright 2017 MinIO, Inc.
  4. *
  5. * Licensed under the Apache License, Version 2.0 (the "License");
  6. * you may not use this file except in compliance with the License.
  7. * You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. */
  17. package credentials
  18. import (
  19. "sync"
  20. "time"
  21. )
  22. const (
  23. // STSVersion sts version string
  24. STSVersion = "2011-06-15"
  25. // How much duration to slash from the given expiration duration
  26. defaultExpiryWindow = 0.8
  27. )
  28. // A Value is the AWS credentials value for individual credential fields.
  29. type Value struct {
  30. // AWS Access key ID
  31. AccessKeyID string
  32. // AWS Secret Access Key
  33. SecretAccessKey string
  34. // AWS Session Token
  35. SessionToken string
  36. // Signature Type.
  37. SignerType SignatureType
  38. }
  39. // A Provider is the interface for any component which will provide credentials
  40. // Value. A provider is required to manage its own Expired state, and what to
  41. // be expired means.
  42. type Provider interface {
  43. // Retrieve returns nil if it successfully retrieved the value.
  44. // Error is returned if the value were not obtainable, or empty.
  45. Retrieve() (Value, error)
  46. // IsExpired returns if the credentials are no longer valid, and need
  47. // to be retrieved.
  48. IsExpired() bool
  49. }
  50. // A Expiry provides shared expiration logic to be used by credentials
  51. // providers to implement expiry functionality.
  52. //
  53. // The best method to use this struct is as an anonymous field within the
  54. // provider's struct.
  55. //
  56. // Example:
  57. // type IAMCredentialProvider struct {
  58. // Expiry
  59. // ...
  60. // }
  61. type Expiry struct {
  62. // The date/time when to expire on
  63. expiration time.Time
  64. // If set will be used by IsExpired to determine the current time.
  65. // Defaults to time.Now if CurrentTime is not set.
  66. CurrentTime func() time.Time
  67. }
  68. // SetExpiration sets the expiration IsExpired will check when called.
  69. //
  70. // If window is greater than 0 the expiration time will be reduced by the
  71. // window value.
  72. //
  73. // Using a window is helpful to trigger credentials to expire sooner than
  74. // the expiration time given to ensure no requests are made with expired
  75. // tokens.
  76. func (e *Expiry) SetExpiration(expiration time.Time, window time.Duration) {
  77. if e.CurrentTime == nil {
  78. e.CurrentTime = time.Now
  79. }
  80. cut := window
  81. if cut < 0 {
  82. expireIn := expiration.Sub(e.CurrentTime())
  83. cut = time.Duration(float64(expireIn) * (1 - defaultExpiryWindow))
  84. }
  85. e.expiration = expiration.Add(-cut)
  86. }
  87. // IsExpired returns if the credentials are expired.
  88. func (e *Expiry) IsExpired() bool {
  89. if e.CurrentTime == nil {
  90. e.CurrentTime = time.Now
  91. }
  92. return e.expiration.Before(e.CurrentTime())
  93. }
  94. // Credentials - A container for synchronous safe retrieval of credentials Value.
  95. // Credentials will cache the credentials value until they expire. Once the value
  96. // expires the next Get will attempt to retrieve valid credentials.
  97. //
  98. // Credentials is safe to use across multiple goroutines and will manage the
  99. // synchronous state so the Providers do not need to implement their own
  100. // synchronization.
  101. //
  102. // The first Credentials.Get() will always call Provider.Retrieve() to get the
  103. // first instance of the credentials Value. All calls to Get() after that
  104. // will return the cached credentials Value until IsExpired() returns true.
  105. type Credentials struct {
  106. sync.Mutex
  107. creds Value
  108. forceRefresh bool
  109. provider Provider
  110. }
  111. // New returns a pointer to a new Credentials with the provider set.
  112. func New(provider Provider) *Credentials {
  113. return &Credentials{
  114. provider: provider,
  115. forceRefresh: true,
  116. }
  117. }
  118. // Get returns the credentials value, or error if the credentials Value failed
  119. // to be retrieved.
  120. //
  121. // Will return the cached credentials Value if it has not expired. If the
  122. // credentials Value has expired the Provider's Retrieve() will be called
  123. // to refresh the credentials.
  124. //
  125. // If Credentials.Expire() was called the credentials Value will be force
  126. // expired, and the next call to Get() will cause them to be refreshed.
  127. func (c *Credentials) Get() (Value, error) {
  128. if c == nil {
  129. return Value{}, nil
  130. }
  131. c.Lock()
  132. defer c.Unlock()
  133. if c.isExpired() {
  134. creds, err := c.provider.Retrieve()
  135. if err != nil {
  136. return Value{}, err
  137. }
  138. c.creds = creds
  139. c.forceRefresh = false
  140. }
  141. return c.creds, nil
  142. }
  143. // Expire expires the credentials and forces them to be retrieved on the
  144. // next call to Get().
  145. //
  146. // This will override the Provider's expired state, and force Credentials
  147. // to call the Provider's Retrieve().
  148. func (c *Credentials) Expire() {
  149. c.Lock()
  150. defer c.Unlock()
  151. c.forceRefresh = true
  152. }
  153. // IsExpired returns if the credentials are no longer valid, and need
  154. // to be refreshed.
  155. //
  156. // If the Credentials were forced to be expired with Expire() this will
  157. // reflect that override.
  158. func (c *Credentials) IsExpired() bool {
  159. c.Lock()
  160. defer c.Unlock()
  161. return c.isExpired()
  162. }
  163. // isExpired helper method wrapping the definition of expired credentials.
  164. func (c *Credentials) isExpired() bool {
  165. return c.forceRefresh || c.provider.IsExpired()
  166. }