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