credentials.go 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  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. // A Value is the AWS credentials value for individual credential fields.
  23. type Value struct {
  24. // AWS Access key ID
  25. AccessKeyID string
  26. // AWS Secret Access Key
  27. SecretAccessKey string
  28. // AWS Session Token
  29. SessionToken string
  30. // Signature Type.
  31. SignerType SignatureType
  32. }
  33. // A Provider is the interface for any component which will provide credentials
  34. // Value. A provider is required to manage its own Expired state, and what to
  35. // be expired means.
  36. type Provider interface {
  37. // Retrieve returns nil if it successfully retrieved the value.
  38. // Error is returned if the value were not obtainable, or empty.
  39. Retrieve() (Value, error)
  40. // IsExpired returns if the credentials are no longer valid, and need
  41. // to be retrieved.
  42. IsExpired() bool
  43. }
  44. // A Expiry provides shared expiration logic to be used by credentials
  45. // providers to implement expiry functionality.
  46. //
  47. // The best method to use this struct is as an anonymous field within the
  48. // provider's struct.
  49. //
  50. // Example:
  51. // type IAMCredentialProvider struct {
  52. // Expiry
  53. // ...
  54. // }
  55. type Expiry struct {
  56. // The date/time when to expire on
  57. expiration time.Time
  58. // If set will be used by IsExpired to determine the current time.
  59. // Defaults to time.Now if CurrentTime is not set.
  60. CurrentTime func() time.Time
  61. }
  62. // SetExpiration sets the expiration IsExpired will check when called.
  63. //
  64. // If window is greater than 0 the expiration time will be reduced by the
  65. // window value.
  66. //
  67. // Using a window is helpful to trigger credentials to expire sooner than
  68. // the expiration time given to ensure no requests are made with expired
  69. // tokens.
  70. func (e *Expiry) SetExpiration(expiration time.Time, window time.Duration) {
  71. e.expiration = expiration
  72. if window > 0 {
  73. e.expiration = e.expiration.Add(-window)
  74. }
  75. }
  76. // IsExpired returns if the credentials are expired.
  77. func (e *Expiry) IsExpired() bool {
  78. if e.CurrentTime == nil {
  79. e.CurrentTime = time.Now
  80. }
  81. return e.expiration.Before(e.CurrentTime())
  82. }
  83. // Credentials - A container for synchronous safe retrieval of credentials Value.
  84. // Credentials will cache the credentials value until they expire. Once the value
  85. // expires the next Get will attempt to retrieve valid credentials.
  86. //
  87. // Credentials is safe to use across multiple goroutines and will manage the
  88. // synchronous state so the Providers do not need to implement their own
  89. // synchronization.
  90. //
  91. // The first Credentials.Get() will always call Provider.Retrieve() to get the
  92. // first instance of the credentials Value. All calls to Get() after that
  93. // will return the cached credentials Value until IsExpired() returns true.
  94. type Credentials struct {
  95. sync.Mutex
  96. creds Value
  97. forceRefresh bool
  98. provider Provider
  99. }
  100. // New returns a pointer to a new Credentials with the provider set.
  101. func New(provider Provider) *Credentials {
  102. return &Credentials{
  103. provider: provider,
  104. forceRefresh: true,
  105. }
  106. }
  107. // Get returns the credentials value, or error if the credentials Value failed
  108. // to be retrieved.
  109. //
  110. // Will return the cached credentials Value if it has not expired. If the
  111. // credentials Value has expired the Provider's Retrieve() will be called
  112. // to refresh the credentials.
  113. //
  114. // If Credentials.Expire() was called the credentials Value will be force
  115. // expired, and the next call to Get() will cause them to be refreshed.
  116. func (c *Credentials) Get() (Value, error) {
  117. c.Lock()
  118. defer c.Unlock()
  119. if c.isExpired() {
  120. creds, err := c.provider.Retrieve()
  121. if err != nil {
  122. return Value{}, err
  123. }
  124. c.creds = creds
  125. c.forceRefresh = false
  126. }
  127. return c.creds, nil
  128. }
  129. // Expire expires the credentials and forces them to be retrieved on the
  130. // next call to Get().
  131. //
  132. // This will override the Provider's expired state, and force Credentials
  133. // to call the Provider's Retrieve().
  134. func (c *Credentials) Expire() {
  135. c.Lock()
  136. defer c.Unlock()
  137. c.forceRefresh = true
  138. }
  139. // IsExpired returns if the credentials are no longer valid, and need
  140. // to be refreshed.
  141. //
  142. // If the Credentials were forced to be expired with Expire() this will
  143. // reflect that override.
  144. func (c *Credentials) IsExpired() bool {
  145. c.Lock()
  146. defer c.Unlock()
  147. return c.isExpired()
  148. }
  149. // isExpired helper method wrapping the definition of expired credentials.
  150. func (c *Credentials) isExpired() bool {
  151. return c.forceRefresh || c.provider.IsExpired()
  152. }