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\Arn\Arn;
-
 
5
use Aws\Exception\CredentialsException;
-
 
6
use GuzzleHttp\Exception\ConnectException;
4
use Aws\Exception\CredentialsException;
7
use GuzzleHttp\Exception\GuzzleException;
-
 
8
use GuzzleHttp\Psr7\Request;
5
use GuzzleHttp\Psr7\Request;
9
use GuzzleHttp\Promise;
6
use GuzzleHttp\Promise\PromiseInterface;
10
use GuzzleHttp\Promise\PromiseInterface;
Línea 7... Línea 11...
7
use Psr\Http\Message\ResponseInterface;
11
use Psr\Http\Message\ResponseInterface;
8
 
12
 
9
/**
13
/**
10
 * Credential provider that fetches credentials with GET request.
14
 * Credential provider that fetches container credentials with GET request.
11
 * ECS environment variable is used in constructing request URI.
15
 * container environment variables are used in constructing request URI.
12
 */
16
 */
13
class EcsCredentialProvider
17
class EcsCredentialProvider
14
{
18
{
15
    const SERVER_URI = 'http://169.254.170.2';
19
    const SERVER_URI = 'http://169.254.170.2';
16
    const ENV_URI = "AWS_CONTAINER_CREDENTIALS_RELATIVE_URI";
20
    const ENV_URI = "AWS_CONTAINER_CREDENTIALS_RELATIVE_URI";
-
 
21
    const ENV_FULL_URI = "AWS_CONTAINER_CREDENTIALS_FULL_URI";
17
    const ENV_FULL_URI = "AWS_CONTAINER_CREDENTIALS_FULL_URI";
22
    const ENV_AUTH_TOKEN = "AWS_CONTAINER_AUTHORIZATION_TOKEN";
-
 
23
    const ENV_AUTH_TOKEN_FILE = "AWS_CONTAINER_AUTHORIZATION_TOKEN_FILE";
-
 
24
    const ENV_TIMEOUT = 'AWS_METADATA_SERVICE_TIMEOUT';
-
 
25
    const EKS_SERVER_HOST_IPV4 = '169.254.170.23';
-
 
26
    const EKS_SERVER_HOST_IPV6 = 'fd00:ec2::23';
-
 
27
    const ENV_RETRIES = 'AWS_METADATA_SERVICE_NUM_ATTEMPTS';
-
 
28
 
Línea 18... Línea 29...
18
    const ENV_AUTH_TOKEN = "AWS_CONTAINER_AUTHORIZATION_TOKEN";
29
    const DEFAULT_ENV_TIMEOUT = 1.0;
19
    const ENV_TIMEOUT = 'AWS_METADATA_SERVICE_TIMEOUT';
30
    const DEFAULT_ENV_RETRIES = 3;
Línea 20... Línea 31...
20
 
31
 
21
    /** @var callable */
32
    /** @var callable */
Línea -... Línea 33...
-
 
33
    private $client;
-
 
34
 
-
 
35
    /** @var float|mixed */
-
 
36
    private $timeout;
-
 
37
 
-
 
38
    /** @var int */
22
    private $client;
39
    private $retries;
23
 
40
 
24
    /** @var float|mixed */
41
    /** @var int */
-
 
42
    private $attempts;
25
    private $timeout;
43
 
26
 
44
    /**
27
    /**
45
     *  The constructor accepts following options:
28
     *  The constructor accepts following options:
46
     *  - timeout: (optional) Connection timeout, in seconds, default 1.0
29
     *  - timeout: (optional) Connection timeout, in seconds, default 1.0
47
     *  - retries: Optional number of retries to be attempted, default 3.
30
     *  - client: An EcsClient to make request from
48
     *  - client: An EcsClient to make request from
31
     *
49
     *
-
 
50
     * @param array $config Configuration options
-
 
51
     */
-
 
52
    public function __construct(array $config = [])
-
 
53
    {
-
 
54
        $this->timeout = (float) isset($config['timeout'])
Línea 32... Línea -...
32
     * @param array $config Configuration options
-
 
33
     */
-
 
34
    public function __construct(array $config = [])
-
 
35
    {
-
 
36
        $timeout = getenv(self::ENV_TIMEOUT);
-
 
37
 
-
 
38
        if (!$timeout) {
-
 
39
            $timeout = isset($_SERVER[self::ENV_TIMEOUT])
-
 
40
                ? $_SERVER[self::ENV_TIMEOUT]
-
 
41
                : (isset($config['timeout']) ? $config['timeout'] : 1.0);
55
            ? $config['timeout']
42
        }
56
            : (getenv(self::ENV_TIMEOUT) ?: self::DEFAULT_ENV_TIMEOUT);
Línea 43... Línea 57...
43
 
57
        $this->retries = (int) isset($config['retries'])
44
        $this->timeout = (float) $timeout;
58
            ? $config['retries']
45
        $this->client = isset($config['client'])
59
            : ((int) getenv(self::ENV_RETRIES) ?: self::DEFAULT_ENV_RETRIES);
46
            ? $config['client']
60
 
-
 
61
        $this->client = $config['client'] ?? \Aws\default_http_handler();
47
            : \Aws\default_http_handler();
62
    }
48
    }
63
 
49
 
64
    /**
-
 
65
     * Load container credentials.
-
 
66
     *
-
 
67
     * @return PromiseInterface
-
 
68
     * @throws GuzzleException
50
    /**
69
     */
51
     * Load ECS credentials
70
    public function __invoke()
52
     *
-
 
53
     * @return PromiseInterface
71
    {
54
     */
72
        $this->attempts = 0;
-
 
73
        $uri = $this->getEcsUri();
-
 
74
        if ($this->isCompatibleUri($uri)) {
55
    public function __invoke()
75
            return Promise\Coroutine::of(function () {
56
    {
76
                $client = $this->client;
57
        $client = $this->client;
77
                $request = new Request('GET', $this->getEcsUri());
58
        $request = new Request('GET', self::getEcsUri());
78
                $headers = $this->getHeadersForAuthToken();
59
        
79
                $credentials = null;
60
        $headers = $this->setHeaderForAuthToken();
80
                while ($credentials === null) {
61
        return $client(
81
                    $credentials = (yield $client(
62
            $request,
82
                        $request,
-
 
83
                        [
-
 
84
                            'timeout' => $this->timeout,
-
 
85
                            'proxy' => '',
-
 
86
                            'headers' => $headers,
-
 
87
                        ]
-
 
88
                    )->then(function (ResponseInterface $response) {
-
 
89
                        $result = $this->decodeResult((string)$response->getBody());
-
 
90
                        if (!isset($result['AccountId']) && isset($result['RoleArn'])) {
-
 
91
                            try {
63
            [
92
                                $parsedArn = new Arn($result['RoleArn']);
64
                'timeout' => $this->timeout,
93
                                $result['AccountId'] = $parsedArn->getAccountId();
65
                'proxy' => '',
94
                            } catch (\Exception $e) {
66
                'headers' => $headers
95
                                // AccountId will be null
67
            ]
96
                            }
-
 
97
                        }
-
 
98
 
68
        )->then(function (ResponseInterface $response) {
99
                        return new Credentials(
69
            $result = $this->decodeResult((string) $response->getBody());
100
                            $result['AccessKeyId'],
70
            return new Credentials(
101
                            $result['SecretAccessKey'],
-
 
102
                            $result['Token'],
-
 
103
                            strtotime($result['Expiration']),
-
 
104
                            $result['AccountId'] ?? null,
-
 
105
                            CredentialSources::ECS
-
 
106
                        );
71
                $result['AccessKeyId'],
107
                    })->otherwise(function ($reason) {
72
                $result['SecretAccessKey'],
108
                        $reason = is_array($reason) ? $reason['exception'] : $reason;
-
 
109
 
-
 
110
                        $isRetryable = $reason instanceof ConnectException;
-
 
111
                        if ($isRetryable && ($this->attempts < $this->retries)) {
-
 
112
                            sleep((int)pow(1.2, $this->attempts));
-
 
113
                        } else {
-
 
114
                            $msg = $reason->getMessage();
-
 
115
                            throw new CredentialsException(
73
                $result['Token'],
116
                                sprintf('Error retrieving credentials from container metadata after attempt %d/%d (%s)', $this->attempts, $this->retries, $msg)
74
                strtotime($result['Expiration'])
117
                            );
75
            );
118
                        }
-
 
119
                    }));
-
 
120
                    $this->attempts++;
-
 
121
                }
-
 
122
 
-
 
123
                yield $credentials;
-
 
124
            });
-
 
125
        }
-
 
126
 
-
 
127
        throw new CredentialsException("Uri '{$uri}' contains an unsupported host.");
-
 
128
    }
-
 
129
 
-
 
130
    /**
76
        })->otherwise(function ($reason) {
131
     * Returns the number of attempts that have been done.
77
            $reason = is_array($reason) ? $reason['exception'] : $reason;
132
     *
-
 
133
     * @return int
-
 
134
     */
-
 
135
    public function getAttempts(): int
-
 
136
    {
-
 
137
        return $this->attempts;
78
            $msg = $reason->getMessage();
138
    }
79
            throw new CredentialsException(
139
 
-
 
140
    /**
-
 
141
     * Retrieves authorization token.
-
 
142
     *
-
 
143
     * @return array|false|string
-
 
144
     */
-
 
145
    private function getEcsAuthToken()
-
 
146
    {
-
 
147
        if (!empty($path = getenv(self::ENV_AUTH_TOKEN_FILE))) {
-
 
148
            $token =  @file_get_contents($path);
-
 
149
            if (false === $token) {
-
 
150
                clearstatcache(true, dirname($path) . DIRECTORY_SEPARATOR . @readlink($path));
-
 
151
                clearstatcache(true, dirname($path) . DIRECTORY_SEPARATOR . dirname(@readlink($path)));
-
 
152
                clearstatcache(true, $path);
-
 
153
            }
-
 
154
 
-
 
155
            if (!is_readable($path)) {
-
 
156
                throw new CredentialsException("Failed to read authorization token from '{$path}': no such file or directory.");
-
 
157
            }
-
 
158
 
-
 
159
            $token = @file_get_contents($path);
-
 
160
 
80
                "Error retrieving credential from ECS ($msg)"
161
            if (empty($token)) {
81
            );
162
                throw new CredentialsException("Invalid authorization token read from `$path`. Token file is empty!");
Línea -... Línea 163...
-
 
163
            }
-
 
164
 
-
 
165
            return $token;
-
 
166
        }
-
 
167
 
-
 
168
        return getenv(self::ENV_AUTH_TOKEN);
-
 
169
    }
-
 
170
 
-
 
171
    /**
-
 
172
     * Provides headers for credential metadata request.
-
 
173
     *
-
 
174
     * @return array|array[]|string[]
-
 
175
     */
-
 
176
    private function getHeadersForAuthToken()
-
 
177
    {
-
 
178
        $authToken = self::getEcsAuthToken();
-
 
179
        $headers = [];
82
        });
180
 
-
 
181
        if (!empty($authToken))
83
    }
182
            $headers = ['Authorization' => $authToken];
84
    
183
 
85
    private function getEcsAuthToken()
184
        return $headers;
86
    {
185
    }
Línea 87... Línea 186...
87
        return getenv(self::ENV_AUTH_TOKEN);
186
 
88
    }
187
    /** @deprecated */
Línea 89... Línea 188...
89
 
188
    public function setHeaderForAuthToken()
90
    public function setHeaderForAuthToken(){
189
    {
91
        $authToken = self::getEcsAuthToken();
190
        $authToken = self::getEcsAuthToken();
92
        $headers = [];
191
        $headers = [];
93
        if(!empty($authToken))
192
        if (!empty($authToken))
94
            $headers = ['Authorization' => $authToken];
193
            $headers = ['Authorization' => $authToken];
95
 
194
 
96
        return $headers;
195
        return $headers;
Línea 97... Línea 196...
97
    }
196
    }
98
 
197
 
99
    /**
198
    /**
Línea 100... Línea 199...
100
     * Fetch credential URI from ECS environment variable
199
     * Fetch container metadata URI from container environment variable.
101
     *
200
     *
102
     * @return string Returns ECS URI
201
     * @return string Returns container metadata URI
103
     */
202
     */
104
    private function getEcsUri()
203
    private function getEcsUri()
Línea 105... Línea 204...
105
    {
204
    {
106
        $credsUri = getenv(self::ENV_URI);
205
        $credsUri = getenv(self::ENV_URI);
107
 
206
 
108
        if ($credsUri === false) {
207
        if ($credsUri === false) {
109
            $credsUri = isset($_SERVER[self::ENV_URI]) ? $_SERVER[self::ENV_URI] : '';
208
            $credsUri = $_SERVER[self::ENV_URI] ?? '';
110
        }
209
        }
Línea 111... Línea 210...
111
 
210
 
112
        if(empty($credsUri)){
211
        if (empty($credsUri)){
113
            $credFullUri = getenv(self::ENV_FULL_URI);
212
            $credFullUri = getenv(self::ENV_FULL_URI);
Línea 114... Línea 213...
114
            if($credFullUri === false){
213
            if ($credFullUri === false){
115
                $credFullUri = isset($_SERVER[self::ENV_FULL_URI]) ? $_SERVER[self::ENV_FULL_URI] : '';
214
                $credFullUri = $_SERVER[self::ENV_FULL_URI] ?? '';
116
            }
215
            }
117
 
216
 
118
            if(!empty($credFullUri))
217
            if (!empty($credFullUri))
-
 
218
                return $credFullUri;
-
 
219
        }
-
 
220
 
-
 
221
        return self::SERVER_URI . $credsUri;
-
 
222
    }
-
 
223
 
-
 
224
    private function decodeResult($response)
-
 
225
    {
-
 
226
        $result = json_decode($response, true);
-
 
227
 
-
 
228
        if (!isset($result['AccessKeyId'])) {
-
 
229
            throw new CredentialsException('Unexpected container metadata credentials value');
-
 
230
        }
-
 
231
        return $result;
-
 
232
    }
-
 
233
 
-
 
234
    /**
-
 
235
     * Determines whether or not a given request URI is a valid
-
 
236
     * container credential request URI.
-
 
237
     *
-
 
238
     * @param $uri
-
 
239
     *
-
 
240
     * @return bool
-
 
241
     */
-
 
242
    private function isCompatibleUri($uri)
-
 
243
    {
-
 
244
        $parsed = parse_url($uri);
-
 
245
 
-
 
246
        if ($parsed['scheme'] !== 'https') {
119
                return $credFullUri;
247
            $host = trim($parsed['host'], '[]');