Proyectos de Subversion Moodle

Rev

Rev 1 | Mostrar el archivo completo | | | Autoría | Ultima modificación | Ver Log |

Rev 1 Rev 1441
Línea 1... Línea 1...
1
<?php
1
<?php
2
namespace Aws\Credentials;
2
namespace Aws\Credentials;
Línea -... Línea 3...
-
 
3
 
3
 
4
use Aws\Configuration\ConfigurationResolver;
4
use Aws\Exception\CredentialsException;
5
use Aws\Exception\CredentialsException;
5
use Aws\Exception\InvalidJsonException;
6
use Aws\Exception\InvalidJsonException;
6
use Aws\Sdk;
7
use Aws\Sdk;
7
use GuzzleHttp\Exception\TransferException;
8
use GuzzleHttp\Exception\TransferException;
8
use GuzzleHttp\Promise;
-
 
9
use GuzzleHttp\Exception\RequestException;
9
use GuzzleHttp\Promise;
10
use GuzzleHttp\Psr7\Request;
10
use GuzzleHttp\Psr7\Request;
11
use GuzzleHttp\Promise\PromiseInterface;
11
use GuzzleHttp\Promise\PromiseInterface;
Línea 12... Línea 12...
12
use Psr\Http\Message\ResponseInterface;
12
use Psr\Http\Message\ResponseInterface;
13
 
13
 
14
/**
14
/**
15
 * Credential provider that provides credentials from the EC2 metadata service.
15
 * Credential provider that provides credentials from the EC2 metadata service.
16
 */
16
 */
17
class InstanceProfileProvider
-
 
18
{
17
class InstanceProfileProvider
19
    const SERVER_URI = 'http://169.254.169.254/latest/';
18
{
20
    const CRED_PATH = 'meta-data/iam/security-credentials/';
-
 
21
    const TOKEN_PATH = 'api/token';
19
    const CRED_PATH = 'meta-data/iam/security-credentials/';
22
 
20
    const TOKEN_PATH = 'api/token';
23
    const ENV_DISABLE = 'AWS_EC2_METADATA_DISABLED';
21
    const ENV_DISABLE = 'AWS_EC2_METADATA_DISABLED';
-
 
22
    const ENV_TIMEOUT = 'AWS_METADATA_SERVICE_TIMEOUT';
-
 
23
    const ENV_RETRIES = 'AWS_METADATA_SERVICE_NUM_ATTEMPTS';
-
 
24
    const CFG_EC2_METADATA_V1_DISABLED = 'ec2_metadata_v1_disabled';
-
 
25
    const CFG_EC2_METADATA_SERVICE_ENDPOINT = 'ec2_metadata_service_endpoint';
-
 
26
    const CFG_EC2_METADATA_SERVICE_ENDPOINT_MODE = 'ec2_metadata_service_endpoint_mode';
-
 
27
    const DEFAULT_TIMEOUT = 1.0;
-
 
28
    const DEFAULT_RETRIES = 3;
-
 
29
    const DEFAULT_TOKEN_TTL_SECONDS = 21600;
-
 
30
    const DEFAULT_AWS_EC2_METADATA_V1_DISABLED = false;
-
 
31
    const ENDPOINT_MODE_IPv4 = 'IPv4';
-
 
32
    const ENDPOINT_MODE_IPv6 = 'IPv6';
Línea 24... Línea 33...
24
    const ENV_TIMEOUT = 'AWS_METADATA_SERVICE_TIMEOUT';
33
    const DEFAULT_METADATA_SERVICE_IPv4_ENDPOINT = 'http://169.254.169.254';
25
    const ENV_RETRIES = 'AWS_METADATA_SERVICE_NUM_ATTEMPTS';
34
    const DEFAULT_METADATA_SERVICE_IPv6_ENDPOINT = 'http://[fd00:ec2::254]';
Línea 26... Línea 35...
26
 
35
 
Línea 40... Línea 49...
40
    private $timeout;
49
    private $timeout;
Línea 41... Línea 50...
41
 
50
 
42
    /** @var bool */
51
    /** @var bool */
Línea -... Línea 52...
-
 
52
    private $secureMode = true;
-
 
53
 
-
 
54
    /** @var bool|null */
-
 
55
    private $ec2MetadataV1Disabled;
-
 
56
 
-
 
57
    /** @var string */
-
 
58
    private $endpoint;
-
 
59
 
-
 
60
    /** @var string */
-
 
61
    private $endpointMode;
-
 
62
 
-
 
63
    /** @var array */
43
    private $secureMode = true;
64
    private $config;
44
 
65
 
45
    /**
66
    /**
46
     * The constructor accepts the following options:
67
     * The constructor accepts the following options:
47
     *
68
     *
48
     * - timeout: Connection timeout, in seconds.
69
     * - timeout: Connection timeout, in seconds.
-
 
70
     * - profile: Optional EC2 profile name, if known.
-
 
71
     * - retries: Optional number of retries to be attempted.
-
 
72
     * - ec2_metadata_v1_disabled: Optional for disabling the fallback to IMDSv1.
-
 
73
     * - endpoint: Optional for overriding the default endpoint to be used for fetching credentials.
-
 
74
     *   The value must contain a valid URI scheme. If the URI scheme is not https, it must
-
 
75
     *   resolve to a loopback address.
-
 
76
     * - endpoint_mode: Optional for overriding the default endpoint mode (IPv4|IPv6) to be used for
-
 
77
     *   resolving the default endpoint.
49
     * - profile: Optional EC2 profile name, if known.
78
     * - use_aws_shared_config_files: Decides whether the shared config file should be considered when
50
     * - retries: Optional number of retries to be attempted.
79
     *   using the ConfigurationResolver::resolve method.
51
     *
80
     *
52
     * @param array $config Configuration options.
81
     * @param array $config Configuration options.
53
     */
82
     */
54
    public function __construct(array $config = [])
83
    public function __construct(array $config = [])
55
    {
84
    {
56
        $this->timeout = (float) getenv(self::ENV_TIMEOUT) ?: (isset($config['timeout']) ? $config['timeout'] : 1.0);
85
        $this->timeout = (float) getenv(self::ENV_TIMEOUT) ?: ($config['timeout'] ?? self::DEFAULT_TIMEOUT);
57
        $this->profile = isset($config['profile']) ? $config['profile'] : null;
86
        $this->profile = $config['profile'] ?? null;
-
 
87
        $this->retries = (int) getenv(self::ENV_RETRIES) ?: ($config['retries'] ?? self::DEFAULT_RETRIES);
58
        $this->retries = (int) getenv(self::ENV_RETRIES) ?: (isset($config['retries']) ? $config['retries'] : 3);
88
        $this->client = $config['client'] ?? \Aws\default_http_handler();
-
 
89
        $this->ec2MetadataV1Disabled = $config[self::CFG_EC2_METADATA_V1_DISABLED] ?? null;
-
 
90
        $this->endpoint = $config[self::CFG_EC2_METADATA_SERVICE_ENDPOINT] ?? null;
-
 
91
        if (!empty($this->endpoint) && !$this->isValidEndpoint($this->endpoint)) {
-
 
92
            throw new \InvalidArgumentException('The provided URI "' . $this->endpoint . '" is invalid, or contains an unsupported host');
-
 
93
        }
59
        $this->client = isset($config['client'])
94
 
60
            ? $config['client'] // internal use only
95
        $this->endpointMode = $config[self::CFG_EC2_METADATA_SERVICE_ENDPOINT_MODE] ?? null;
Línea 61... Línea 96...
61
            : \Aws\default_http_handler();
96
        $this->config = $config;
62
    }
97
    }
63
 
98
 
Línea 77... Línea 112...
77
                try {
112
                try {
78
                    $token = (yield $this->request(
113
                    $token = (yield $this->request(
79
                        self::TOKEN_PATH,
114
                        self::TOKEN_PATH,
80
                        'PUT',
115
                        'PUT',
81
                        [
116
                        [
82
                            'x-aws-ec2-metadata-token-ttl-seconds' => 21600
117
                            'x-aws-ec2-metadata-token-ttl-seconds' => self::DEFAULT_TOKEN_TTL_SECONDS
83
                        ]
118
                        ]
84
                    ));
119
                    ));
85
                } catch (TransferException $e) {
120
                } catch (TransferException $e) {
86
                    if ($this->getExceptionStatusCode($e) === 500
121
                    if ($this->getExceptionStatusCode($e) === 500
87
                        && $previousCredentials instanceof Credentials
122
                        && $previousCredentials instanceof Credentials
88
                    ) {
123
                    ) {
89
                        goto generateCredentials;
124
                        goto generateCredentials;
90
                    }
125
                    } elseif ($this->shouldFallbackToIMDSv1()
91
                    else if (!method_exists($e, 'getResponse')
126
                        && (!method_exists($e, 'getResponse')
92
                        || empty($e->getResponse())
127
                        || empty($e->getResponse())
93
                        || !in_array(
128
                        || !in_array(
94
                            $e->getResponse()->getStatusCode(),
129
                            $e->getResponse()->getStatusCode(),
95
                            [400, 500, 502, 503, 504]
130
                            [400, 500, 502, 503, 504]
96
                        )
131
                        ))
97
                    ) {
132
                    ) {
98
                        $this->secureMode = false;
133
                        $this->secureMode = false;
99
                    } else {
134
                    } else {
100
                        $this->handleRetryableException(
135
                        $this->handleRetryableException(
101
                            $e,
136
                            $e,
Línea 167... Línea 202...
167
                    if (($this->getExceptionStatusCode($e) === 500
202
                    if (($this->getExceptionStatusCode($e) === 500
168
                            || strpos($e->getMessage(), "cURL error 28") !== false)
203
                            || strpos($e->getMessage(), "cURL error 28") !== false)
169
                        && $previousCredentials instanceof Credentials
204
                        && $previousCredentials instanceof Credentials
170
                    ) {
205
                    ) {
171
                        goto generateCredentials;
206
                        goto generateCredentials;
172
                    } else if (!empty($this->getExceptionStatusCode($e))
207
                    } elseif (!empty($this->getExceptionStatusCode($e))
173
                        && $this->getExceptionStatusCode($e) === 401
208
                        && $this->getExceptionStatusCode($e) === 401
174
                    ) {
209
                    ) {
175
                        $this->secureMode = true;
210
                        $this->secureMode = true;
176
                    }
211
                    }
177
                    $this->handleRetryableException(
212
                    $this->handleRetryableException(
Línea 189... Línea 224...
189
            } else {
224
            } else {
190
                $credentials = new Credentials(
225
                $credentials = new Credentials(
191
                    $result['AccessKeyId'],
226
                    $result['AccessKeyId'],
192
                    $result['SecretAccessKey'],
227
                    $result['SecretAccessKey'],
193
                    $result['Token'],
228
                    $result['Token'],
194
                    strtotime($result['Expiration'])
229
                    strtotime($result['Expiration']),
-
 
230
                    $result['AccountId'] ?? null,
-
 
231
                    CredentialSources::IMDS
195
                );
232
                );
196
            }
233
            }
Línea 197... Línea 234...
197
 
234
 
198
            if ($credentials->isExpired()) {
235
            if ($credentials->isExpired()) {
Línea 218... Línea 255...
218
                $this->createErrorMessage('EC2 metadata service access disabled')
255
                $this->createErrorMessage('EC2 metadata service access disabled')
219
            );
256
            );
220
        }
257
        }
Línea 221... Línea 258...
221
 
258
 
222
        $fn = $this->client;
259
        $fn = $this->client;
223
        $request = new Request($method, self::SERVER_URI . $url);
260
        $request = new Request($method, $this->resolveEndpoint() . $url);
224
        $userAgent = 'aws-sdk-php/' . Sdk::VERSION;
261
        $userAgent = 'aws-sdk-php/' . Sdk::VERSION;
225
        if (defined('HHVM_VERSION')) {
262
        if (defined('HHVM_VERSION')) {
226
            $userAgent .= ' HHVM/' . HHVM_VERSION;
263
            $userAgent .= ' HHVM/' . HHVM_VERSION;
227
        }
264
        }
Línea 294... Línea 331...
294
                .  'response code: ' . $result['Code']);
331
                .  'response code: ' . $result['Code']);
295
        }
332
        }
Línea 296... Línea 333...
296
 
333
 
297
        return $result;
334
        return $result;
-
 
335
    }
-
 
336
 
-
 
337
    /**
-
 
338
     * This functions checks for whether we should fall back to IMDSv1 or not.
-
 
339
     * If $ec2MetadataV1Disabled is null then we will try to resolve this value from
-
 
340
     * the following sources:
-
 
341
     * - From environment: "AWS_EC2_METADATA_V1_DISABLED".
-
 
342
     * - From config file: aws_ec2_metadata_v1_disabled
-
 
343
     * - Defaulted to false
-
 
344
     *
-
 
345
     * @return bool
-
 
346
     */
-
 
347
    private function shouldFallbackToIMDSv1(): bool
-
 
348
    {
-
 
349
        $isImdsV1Disabled = \Aws\boolean_value($this->ec2MetadataV1Disabled)
-
 
350
            ?? \Aws\boolean_value(
-
 
351
                ConfigurationResolver::resolve(
-
 
352
                    self::CFG_EC2_METADATA_V1_DISABLED,
-
 
353
                    self::DEFAULT_AWS_EC2_METADATA_V1_DISABLED,
-
 
354
                    'bool',
-
 
355
                    $this->config
-
 
356
                )
-
 
357
            )
-
 
358
            ?? self::DEFAULT_AWS_EC2_METADATA_V1_DISABLED;
-
 
359
 
-
 
360
        return !$isImdsV1Disabled;
-
 
361
    }
-
 
362
 
-
 
363
    /**
-
 
364
     * Resolves the metadata service endpoint. If the endpoint is not provided
-
 
365
     * or configured then, the default endpoint, based on the endpoint mode resolved,
-
 
366
     * will be used.
-
 
367
     * Example: if endpoint_mode is resolved to be IPv4 and the endpoint is not provided
-
 
368
     * then, the endpoint to be used will be http://169.254.169.254.
-
 
369
     *
-
 
370
     * @return string
-
 
371
     */
-
 
372
    private function resolveEndpoint(): string
-
 
373
    {
-
 
374
        $endpoint = $this->endpoint;
-
 
375
        if (is_null($endpoint)) {
-
 
376
            $endpoint = ConfigurationResolver::resolve(
-
 
377
                self::CFG_EC2_METADATA_SERVICE_ENDPOINT,
-
 
378
                $this->getDefaultEndpoint(),
-
 
379
                'string',
-
 
380
                $this->config
-
 
381
            );
-
 
382
        }
-
 
383
 
-
 
384
        if (!$this->isValidEndpoint($endpoint)) {
-
 
385
            throw new CredentialsException('The provided URI "' . $endpoint . '" is invalid, or contains an unsupported host');
-
 
386
        }
-
 
387
 
-
 
388
        if (substr($endpoint, strlen($endpoint) - 1) !== '/') {
-
 
389
            $endpoint = $endpoint . '/';
-
 
390
        }
-
 
391
 
-
 
392
        return $endpoint . 'latest/';
-
 
393
    }
-
 
394
 
-
 
395
    /**
-
 
396
     * Resolves the default metadata service endpoint.
-
 
397
     * If endpoint_mode is resolved as IPv4 then:
-
 
398
     * - endpoint = http://169.254.169.254
-
 
399
     * If endpoint_mode is resolved as IPv6 then:
-
 
400
     * - endpoint = http://[fd00:ec2::254]
-
 
401
     *
-
 
402
     * @return string
-
 
403
     */
-
 
404
    private function getDefaultEndpoint(): string
-
 
405
    {
-
 
406
        $endpointMode = $this->resolveEndpointMode();
-
 
407
        switch ($endpointMode) {
-
 
408
            case self::ENDPOINT_MODE_IPv4:
-
 
409
                return self::DEFAULT_METADATA_SERVICE_IPv4_ENDPOINT;
-
 
410
            case self::ENDPOINT_MODE_IPv6:
-
 
411
                return self::DEFAULT_METADATA_SERVICE_IPv6_ENDPOINT;
-
 
412
        }
-
 
413
 
-
 
414
        throw new CredentialsException("Invalid endpoint mode '$endpointMode' resolved");
-
 
415
    }
-
 
416
 
-
 
417
    /**
-
 
418
     * Resolves the endpoint mode to be considered when resolving the default
-
 
419
     * metadata service endpoint.
-
 
420
     *
-
 
421
     * @return string
-
 
422
     */
-
 
423
    private function resolveEndpointMode(): string
-
 
424
    {
-
 
425
        $endpointMode = $this->endpointMode;
-
 
426
        if (is_null($endpointMode)) {
-
 
427
            $endpointMode = ConfigurationResolver::resolve(
-
 
428
                self::CFG_EC2_METADATA_SERVICE_ENDPOINT_MODE,
-
 
429
                    self::ENDPOINT_MODE_IPv4,
-
 
430
                'string',
-
 
431
                $this->config
-
 
432
            );
-
 
433
        }
-
 
434
 
-
 
435
        return $endpointMode;
-
 
436
    }
-
 
437
 
-
 
438
    /**
-
 
439
     * This method checks for whether a provide URI is valid.
-
 
440
     * @param string $uri this parameter is the uri to do the validation against to.
-
 
441
     *
-
 
442
     * @return string|null
-
 
443
     */
-
 
444
    private function isValidEndpoint(
-
 
445
        $uri
-
 
446
    ): bool
-
 
447
    {
-
 
448
        // We make sure first the provided uri is a valid URL
-
 
449
        $isValidURL = filter_var($uri, FILTER_VALIDATE_URL) !== false;
-
 
450
        if (!$isValidURL) {
-
 
451
            return false;
-
 
452
        }
-
 
453
 
-
 
454
        // We make sure that if is a no secure host then it must be a loop back address.
-
 
455
        $parsedUri = parse_url($uri);
-
 
456
        if ($parsedUri['scheme'] !== 'https') {
-
 
457
            $host = trim($parsedUri['host'], '[]');
-
 
458
 
-
 
459
            return CredentialsUtils::isLoopBackAddress(gethostbyname($host))
-
 
460
                || in_array(
-
 
461
                    $uri,
-
 
462
                    [self::DEFAULT_METADATA_SERVICE_IPv4_ENDPOINT, self::DEFAULT_METADATA_SERVICE_IPv6_ENDPOINT]
-
 
463
                );
-
 
464
        }
-
 
465
 
-
 
466
        return true;
298
    }
467
    }