Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 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
 
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