Proyectos de Subversion Moodle

Rev

Rev 1 | | Comparar con el anterior | Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
<?php
2
namespace Aws\Credentials;
3
 
4
use Aws\Exception\AwsException;
5
use Aws\Exception\CredentialsException;
6
use Aws\Result;
7
use Aws\Sts\StsClient;
8
use GuzzleHttp\Promise;
9
 
10
/**
11
 * Credential provider that provides credentials via assuming a role with a web identity
12
 * More Information, see: https://docs.aws.amazon.com/aws-sdk-php/v3/api/api-sts-2011-06-15.html#assumerolewithwebidentity
13
 */
14
class AssumeRoleWithWebIdentityCredentialProvider
15
{
16
    const ERROR_MSG = "Missing required 'AssumeRoleWithWebIdentityCredentialProvider' configuration option: ";
17
    const ENV_RETRIES = 'AWS_METADATA_SERVICE_NUM_ATTEMPTS';
18
 
19
    /** @var string */
20
    private $tokenFile;
21
 
22
    /** @var string */
23
    private $arn;
24
 
25
    /** @var string */
26
    private $session;
27
 
28
    /** @var StsClient */
29
    private $client;
30
 
31
    /** @var integer */
32
    private $retries;
33
 
34
    /** @var integer */
35
    private $authenticationAttempts;
36
 
37
    /** @var integer */
38
    private $tokenFileReadAttempts;
1441 ariadna 39
    /** @var string */
40
    private $source;
1 efrain 41
 
42
    /**
43
     * The constructor attempts to load config from environment variables.
44
     * If not set, the following config options are used:
45
     *  - WebIdentityTokenFile: full path of token filename
46
     *  - RoleArn: arn of role to be assumed
47
     *  - SessionName: (optional) set by SDK if not provided
1441 ariadna 48
     *  - source: To identify if the provider was sourced by a profile or
49
     *    from environment definition. Default will be `sts_web_id_token`.
1 efrain 50
     *
51
     * @param array $config Configuration options
52
     * @throws \InvalidArgumentException
53
     */
54
    public function __construct(array $config = [])
55
    {
56
        if (!isset($config['RoleArn'])) {
57
            throw new \InvalidArgumentException(self::ERROR_MSG . "'RoleArn'.");
58
        }
59
        $this->arn = $config['RoleArn'];
60
 
61
        if (!isset($config['WebIdentityTokenFile'])) {
62
            throw new \InvalidArgumentException(self::ERROR_MSG . "'WebIdentityTokenFile'.");
63
        }
64
        $this->tokenFile = $config['WebIdentityTokenFile'];
65
 
66
        if (!preg_match("/^\w\:|^\/|^\\\/", $this->tokenFile)) {
67
            throw new \InvalidArgumentException("'WebIdentityTokenFile' must be an absolute path.");
68
        }
69
 
70
        $this->retries = (int) getenv(self::ENV_RETRIES) ?: (isset($config['retries']) ? $config['retries'] : 3);
71
        $this->authenticationAttempts = 0;
72
        $this->tokenFileReadAttempts = 0;
1441 ariadna 73
        $this->session = $config['SessionName']
74
            ?? 'aws-sdk-php-' . round(microtime(true) * 1000);
75
        $region = $config['region'] ?? 'us-east-1';
1 efrain 76
        if (isset($config['client'])) {
77
            $this->client = $config['client'];
78
        } else {
79
            $this->client = new StsClient([
80
                'credentials' => false,
81
                'region' => $region,
82
                'version' => 'latest'
83
            ]);
84
        }
1441 ariadna 85
 
86
        $this->source = $config['source']
87
            ?? CredentialSources::STS_WEB_ID_TOKEN;
1 efrain 88
    }
89
 
90
    /**
91
     * Loads assume role with web identity credentials.
92
     *
93
     * @return Promise\PromiseInterface
94
     */
95
    public function __invoke()
96
    {
97
        return Promise\Coroutine::of(function () {
98
            $client = $this->client;
99
            $result = null;
100
            while ($result == null) {
101
                try {
102
                    $token = @file_get_contents($this->tokenFile);
103
                    if (false === $token) {
104
                        clearstatcache(true, dirname($this->tokenFile) . "/" . readlink($this->tokenFile));
105
                        clearstatcache(true, dirname($this->tokenFile) . "/" . dirname(readlink($this->tokenFile)));
106
                        clearstatcache(true, $this->tokenFile);
107
                        if (!@is_readable($this->tokenFile)) {
108
                            throw new CredentialsException(
109
                                "Unreadable tokenfile at location {$this->tokenFile}"
110
                            );
111
                        }
112
 
113
                        $token = @file_get_contents($this->tokenFile);
114
                    }
115
                    if (empty($token)) {
116
                        if ($this->tokenFileReadAttempts < $this->retries) {
117
                            sleep((int) pow(1.2, $this->tokenFileReadAttempts));
118
                            $this->tokenFileReadAttempts++;
119
                            continue;
120
                        }
121
                        throw new CredentialsException("InvalidIdentityToken from file: {$this->tokenFile}");
122
                    }
123
                } catch (\Exception $exception) {
124
                    throw new CredentialsException(
125
                        "Error reading WebIdentityTokenFile from " . $this->tokenFile,
126
                        0,
127
                        $exception
128
                    );
129
                }
130
 
131
                $assumeParams = [
132
                    'RoleArn' => $this->arn,
133
                    'RoleSessionName' => $this->session,
134
                    'WebIdentityToken' => $token
135
                ];
136
 
137
                try {
138
                    $result = $client->assumeRoleWithWebIdentity($assumeParams);
139
                } catch (AwsException $e) {
140
                    if ($e->getAwsErrorCode() == 'InvalidIdentityToken') {
141
                        if ($this->authenticationAttempts < $this->retries) {
142
                            sleep((int) pow(1.2, $this->authenticationAttempts));
143
                        } else {
144
                            throw new CredentialsException(
145
                                "InvalidIdentityToken, retries exhausted"
146
                            );
147
                        }
148
                    } else {
149
                        throw new CredentialsException(
150
                            "Error assuming role from web identity credentials",
151
                            0,
152
                            $e
153
                        );
154
                    }
155
                } catch (\Exception $e) {
156
                    throw new CredentialsException(
157
                        "Error retrieving web identity credentials: " . $e->getMessage()
158
                        . " (" . $e->getCode() . ")"
159
                    );
160
                }
161
                $this->authenticationAttempts++;
162
            }
163
 
1441 ariadna 164
            yield $this->client->createCredentials(
165
                $result,
166
                $this->source
167
            );
1 efrain 168
        });
169
    }
170
}