PluginProbe ʕ •ᴥ•ʔ
Transferito: WP Migration / trunk
Transferito: WP Migration vtrunk
trunk 11.4.0 12.0.0 13.1.0 14.0.0 14.0.11 14.0.7 14.1.0 14.1.1 14.1.2 14.1.3 14.1.4
transferito / vendor / aws / aws-sdk-php / src / Token / TokenProvider.php
transferito / vendor / aws / aws-sdk-php / src / Token Last commit date
BearerTokenAuthorization.php 11 months ago ParsesIniTrait.php 11 months ago RefreshableTokenProviderInterface.php 11 months ago SsoToken.php 11 months ago SsoTokenProvider.php 11 months ago Token.php 11 months ago TokenAuthorization.php 11 months ago TokenInterface.php 11 months ago TokenProvider.php 11 months ago
TokenProvider.php
269 lines
1 <?php
2 namespace Aws\Token;
3
4 use Aws;
5 use Aws\Api\DateTimeResult;
6 use Aws\CacheInterface;
7 use Aws\Exception\TokenException;
8 use GuzzleHttp\Promise;
9
10 /**
11 * Token providers are functions that accept no arguments and return a
12 * promise that is fulfilled with an {@see \Aws\Token\TokenInterface}
13 * or rejected with an {@see \Aws\Exception\TokenException}.
14 *
15 * <code>
16 * use Aws\Token\TokenProvider;
17 * $provider = TokenProvider::defaultProvider();
18 * // Returns a TokenInterface or throws.
19 * $token = $provider()->wait();
20 * </code>
21 *
22 * Token providers can be composed to create a token using conditional
23 * logic that can create different tokens in different environments. You
24 * can compose multiple providers into a single provider using
25 * {@see Aws\Token\TokenProvider::chain}. This function accepts
26 * providers as variadic arguments and returns a new function that will invoke
27 * each provider until a token is successfully returned.
28 */
29 class TokenProvider
30 {
31 use ParsesIniTrait;
32 const ENV_PROFILE = 'AWS_PROFILE';
33
34 /**
35 * Create a default token provider tha checks for cached a SSO token from
36 * the CLI
37 *
38 * This provider is automatically wrapped in a memoize function that caches
39 * previously provided tokens.
40 *
41 * @param array $config Optional array of token provider options.
42 *
43 * @return callable
44 */
45 public static function defaultProvider(array $config = [])
46 {
47
48 $cacheable = [
49 'sso',
50 ];
51
52 $defaultChain = [];
53
54 if (
55 !isset($config['use_aws_shared_config_files'])
56 || $config['use_aws_shared_config_files'] !== false
57 ) {
58 $profileName = getenv(self::ENV_PROFILE) ?: 'default';
59 $defaultChain['sso'] = self::sso(
60 $profileName,
61 self::getHomeDir() . '/.aws/config',
62 $config
63 );
64 }
65
66 if (isset($config['token'])
67 && $config['token'] instanceof CacheInterface
68 ) {
69 foreach ($cacheable as $provider) {
70 if (isset($defaultChain[$provider])) {
71 $defaultChain[$provider] = self::cache(
72 $defaultChain[$provider],
73 $config['token'],
74 'aws_cached_' . $provider . '_token'
75 );
76 }
77 }
78 }
79
80 return self::memoize(
81 call_user_func_array(
82 [TokenProvider::class, 'chain'],
83 array_values($defaultChain)
84 )
85 );
86 }
87
88 /**
89 * Create a token provider function from a static token.
90 *
91 * @param TokenInterface $token
92 *
93 * @return callable
94 */
95 public static function fromToken(TokenInterface $token)
96 {
97 $promise = Promise\Create::promiseFor($token);
98
99 return function () use ($promise) {
100 return $promise;
101 };
102 }
103
104 /**
105 * Creates an aggregate token provider that invokes the provided
106 * variadic providers one after the other until a provider returns
107 * a token.
108 *
109 * @return callable
110 */
111 public static function chain()
112 {
113 $links = func_get_args();
114 //Common use case for when aws_shared_config_files is false
115 if (empty($links)) {
116 return function () {
117 return Promise\Create::promiseFor(false);
118 };
119 }
120
121 return function () use ($links) {
122 /** @var callable $parent */
123 $parent = array_shift($links);
124 $promise = $parent();
125 while ($next = array_shift($links)) {
126 $promise = $promise->otherwise($next);
127 }
128 return $promise;
129 };
130 }
131
132 /**
133 * Wraps a token provider and caches a previously provided token.
134 * Ensures that cached tokens are refreshed when they expire.
135 *
136 * @param callable $provider Token provider function to wrap.
137 * @return callable
138 */
139 public static function memoize(callable $provider)
140 {
141 return function () use ($provider) {
142 static $result;
143 static $isConstant;
144
145 // Constant tokens will be returned constantly.
146 if ($isConstant) {
147 return $result;
148 }
149
150 // Create the initial promise that will be used as the cached value
151 // until it expires.
152 if (null === $result) {
153 $result = $provider();
154 }
155
156 // Return a token that could expire and refresh when needed.
157 return $result
158 ->then(function (TokenInterface $token) use ($provider, &$isConstant, &$result) {
159 // Determine if the token is constant.
160 if (!$token->getExpiration()) {
161 $isConstant = true;
162 return $token;
163 }
164
165 if (!$token->isExpired()) {
166 return $token;
167 }
168 return $result = $provider();
169 })
170 ->otherwise(function($reason) use (&$result) {
171 // Cleanup rejected promise.
172 $result = null;
173 return Promise\Create::promiseFor(null);
174 });
175 };
176 }
177
178 /**
179 * Wraps a token provider and saves provided token in an
180 * instance of Aws\CacheInterface. Forwards calls when no token found
181 * in cache and updates cache with the results.
182 *
183 * @param callable $provider Token provider function to wrap
184 * @param CacheInterface $cache Cache to store the token
185 * @param string|null $cacheKey (optional) Cache key to use
186 *
187 * @return callable
188 */
189 public static function cache(
190 callable $provider,
191 CacheInterface $cache,
192 $cacheKey = null
193 ) {
194 $cacheKey = $cacheKey ?: 'aws_cached_token';
195
196 return function () use ($provider, $cache, $cacheKey) {
197 $found = $cache->get($cacheKey);
198 if (is_array($found) && isset($found['token'])) {
199 if (isset($found['token']) && $found['token'] instanceof TokenInterface) {
200 $foundToken = $found['token'];
201 if (!$foundToken->isExpired()) {
202 return Promise\Create::promiseFor($foundToken);
203 }
204 if (isset($found['refreshMethod']) && is_callable($found['refreshMethod'])) {
205 return Promise\Create::promiseFor($found['refreshMethod']());
206 }
207 }
208 }
209
210 return $provider()
211 ->then(function (TokenInterface $token) use (
212 $cache,
213 $cacheKey
214 ) {
215 $cache->set(
216 $cacheKey,
217 $token,
218 null === $token->getExpiration() ?
219 0 : $token->getExpiration() - time()
220 );
221
222 return $token;
223 });
224 };
225 }
226
227 /**
228 * Gets profiles from the ~/.aws/config ini file
229 */
230 private static function loadDefaultProfiles() {
231 $profiles = [];
232 $configFile = self::getHomeDir() . '/.aws/config';
233
234 if (file_exists($configFile)) {
235 $configProfileData = \Aws\parse_ini_file($configFile, true, INI_SCANNER_RAW);
236 foreach ($configProfileData as $name => $profile) {
237 // standardize config profile names
238 $name = str_replace('profile ', '', $name);
239 if (!isset($profiles[$name])) {
240 $profiles[$name] = $profile;
241 }
242 }
243 }
244
245 return $profiles;
246 }
247
248 private static function reject($msg)
249 {
250 return new Promise\RejectedPromise(new TokenException($msg));
251 }
252
253 /**
254 * Token provider that creates a token from cached sso credentials
255 *
256 * @param string $ssoProfileName the name of the ini profile name
257 * @param string $filename the location of the ini file
258 * @param array $config configuration options
259 *
260 * @return SsoToken
261 * @see Aws\Token\SsoToken for $config details.
262 */
263 public static function sso($profileName, $filename, $config = [])
264 {
265 return new SsoTokenProvider($profileName, $filename, $config);
266 }
267 }
268
269