Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
<?php
2
namespace Aws\Endpoint;
3
 
4
use ArrayAccess;
5
use Aws\HasDataTrait;
6
use Aws\Sts\RegionalEndpoints\ConfigurationProvider;
7
use Aws\S3\RegionalEndpoint\ConfigurationProvider as S3ConfigurationProvider;
8
use InvalidArgumentException as Iae;
9
 
10
/**
11
 * Default implementation of an AWS partition.
12
 */
13
final class Partition implements ArrayAccess, PartitionInterface
14
{
15
    use HasDataTrait;
16
 
17
    private $stsLegacyGlobalRegions = [
18
        'ap-northeast-1',
19
        'ap-south-1',
20
        'ap-southeast-1',
21
        'ap-southeast-2',
22
        'aws-global',
23
        'ca-central-1',
24
        'eu-central-1',
25
        'eu-north-1',
26
        'eu-west-1',
27
        'eu-west-2',
28
        'eu-west-3',
29
        'sa-east-1',
30
        'us-east-1',
31
        'us-east-2',
32
        'us-west-1',
33
        'us-west-2',
34
    ];
35
 
36
    /**
37
     * The partition constructor accepts the following options:
38
     *
39
     * - `partition`: (string, required) The partition name as specified in an
40
     *   ARN (e.g., `aws`)
41
     * - `partitionName`: (string) The human readable name of the partition
42
     *   (e.g., "AWS Standard")
43
     * - `dnsSuffix`: (string, required) The DNS suffix of the partition. This
44
     *   value is used to determine how endpoints in the partition are resolved.
45
     * - `regionRegex`: (string) A PCRE regular expression that specifies the
46
     *   pattern that region names in the endpoint adhere to.
47
     * - `regions`: (array, required) A map of the regions in the partition.
48
     *   Each key is the region as present in a hostname (e.g., `us-east-1`),
49
     *   and each value is a structure containing region information.
50
     * - `defaults`: (array) A map of default key value pairs to apply to each
51
     *   endpoint of the partition. Any value in an `endpoint` definition will
52
     *   supersede any values specified in `defaults`.
53
     * - `services`: (array, required) A map of service endpoint prefix name
54
     *   (the value found in a hostname) to information about the service.
55
     *
56
     * @param array $definition
57
     *
58
     * @throws Iae if any required options are missing
59
     */
60
    public function __construct(array $definition)
61
    {
62
        foreach (['partition', 'regions', 'services', 'dnsSuffix'] as $key) {
63
            if (!isset($definition[$key])) {
64
                throw new Iae("Partition missing required $key field");
65
            }
66
        }
67
 
68
        $this->data = $definition;
69
    }
70
 
71
    public function getName()
72
    {
73
        return $this->data['partition'];
74
    }
75
 
76
    /**
77
     * @internal
78
     * @return mixed
79
     */
80
    public function getDnsSuffix()
81
    {
82
        return $this->data['dnsSuffix'];
83
    }
84
 
85
    public function isRegionMatch($region, $service)
86
    {
87
        if (isset($this->data['regions'][$region])
88
            || isset($this->data['services'][$service]['endpoints'][$region])
89
        ) {
90
            return true;
91
        }
92
 
93
        if (isset($this->data['regionRegex'])) {
94
            return (bool) preg_match(
95
                "@{$this->data['regionRegex']}@",
96
                $region
97
            );
98
        }
99
 
100
        return false;
101
    }
102
 
103
    public function getAvailableEndpoints(
104
        $service,
105
        $allowNonRegionalEndpoints = false
106
    ) {
107
        if ($this->isServicePartitionGlobal($service)) {
108
            return [$this->getPartitionEndpoint($service)];
109
        }
110
 
111
        if (isset($this->data['services'][$service]['endpoints'])) {
112
            $serviceRegions = array_keys(
113
                $this->data['services'][$service]['endpoints']
114
            );
115
 
116
            return $allowNonRegionalEndpoints
117
                ? $serviceRegions
118
                : array_intersect($serviceRegions, array_keys(
119
                    $this->data['regions']
120
                ));
121
        }
122
 
123
        return [];
124
    }
125
 
126
    public function __invoke(array $args = [])
127
    {
128
        $service = isset($args['service']) ? $args['service'] : '';
129
        $region = isset($args['region']) ? $args['region'] : '';
130
        $scheme = isset($args['scheme']) ? $args['scheme'] : 'https';
131
        $options = isset($args['options']) ? $args['options'] : [];
132
        $data = $this->getEndpointData($service, $region, $options);
133
        $variant = $this->getVariant($options, $data);
134
        if (isset($variant['hostname'])) {
135
            $template = $variant['hostname'];
136
        } else {
137
            $template = isset($data['hostname']) ? $data['hostname'] : '';
138
        }
139
        $dnsSuffix = isset($variant['dnsSuffix'])
140
            ? $variant['dnsSuffix']
141
            : $this->data['dnsSuffix'];
142
        return [
143
            'endpoint' => "{$scheme}://" . $this->formatEndpoint(
144
                    $template,
145
                    $service,
146
                    $region,
147
                    $dnsSuffix
148
                ),
149
            'signatureVersion' => $this->getSignatureVersion($data),
150
            'signingRegion' => isset($data['credentialScope']['region'])
151
                ? $data['credentialScope']['region']
152
                : $region,
153
            'signingName' => isset($data['credentialScope']['service'])
154
                ? $data['credentialScope']['service']
155
                : $service,
156
        ];
157
    }
158
 
159
    private function getEndpointData($service, $region, $options)
160
    {
161
        $defaultRegion = $this->resolveRegion($service, $region, $options);
162
        $data = isset($this->data['services'][$service]['endpoints'][$defaultRegion])
163
            ? $this->data['services'][$service]['endpoints'][$defaultRegion]
164
            : [];
165
        $data += isset($this->data['services'][$service]['defaults'])
166
            ? $this->data['services'][$service]['defaults']
167
            : [];
168
        $data += isset($this->data['defaults'])
169
            ? $this->data['defaults']
170
            : [];
171
 
172
        return $data;
173
    }
174
 
175
    private function getSignatureVersion(array $data)
176
    {
177
        static $supportedBySdk = [
178
            's3v4',
179
            'v4',
180
            'anonymous',
181
        ];
182
 
183
        $possibilities = array_intersect(
184
            $supportedBySdk,
185
            isset($data['signatureVersions'])
186
                ? $data['signatureVersions']
187
                : ['v4']
188
        );
189
 
190
        return array_shift($possibilities);
191
    }
192
 
193
    private function resolveRegion($service, $region, $options)
194
    {
195
        if (isset($this->data['services'][$service]['endpoints'][$region])
196
            && $this->isFipsEndpointUsed($region)
197
        ) {
198
            return $region;
199
        }
200
 
201
        if ($this->isServicePartitionGlobal($service)
202
            || $this->isStsLegacyEndpointUsed($service, $region, $options)
203
            || $this->isS3LegacyEndpointUsed($service, $region, $options)
204
        ) {
205
            return $this->getPartitionEndpoint($service);
206
        }
207
 
208
        return $region;
209
    }
210
 
211
    private function isServicePartitionGlobal($service)
212
    {
213
        return isset($this->data['services'][$service]['isRegionalized'])
214
            && false === $this->data['services'][$service]['isRegionalized']
215
            && isset($this->data['services'][$service]['partitionEndpoint']);
216
    }
217
 
218
    /**
219
     * STS legacy endpoints used for valid regions unless option is explicitly
220
     * set to 'regional'
221
     *
222
     * @param string $service
223
     * @param string $region
224
     * @param array $options
225
     * @return bool
226
     */
227
    private function isStsLegacyEndpointUsed($service, $region, $options)
228
    {
229
        return $service === 'sts'
230
            && in_array($region, $this->stsLegacyGlobalRegions)
231
            && (empty($options['sts_regional_endpoints'])
232
                || ConfigurationProvider::unwrap(
233
                    $options['sts_regional_endpoints']
234
                )->getEndpointsType() !== 'regional'
235
            );
236
    }
237
 
238
    /**
239
     * S3 legacy us-east-1 endpoint used for valid regions unless option is explicitly
240
     * set to 'regional'
241
     *
242
     * @param string $service
243
     * @param string $region
244
     * @param array $options
245
     * @return bool
246
     */
247
    private function isS3LegacyEndpointUsed($service, $region, $options)
248
    {
249
        return $service === 's3'
250
            && $region === 'us-east-1'
251
            && (empty($options['s3_us_east_1_regional_endpoint'])
252
                || S3ConfigurationProvider::unwrap(
253
                    $options['s3_us_east_1_regional_endpoint']
254
                )->getEndpointsType() !== 'regional'
255
            );
256
    }
257
 
258
    private function getPartitionEndpoint($service)
259
    {
260
        return $this->data['services'][$service]['partitionEndpoint'];
261
    }
262
 
263
    private function formatEndpoint($template, $service, $region, $dnsSuffix)
264
    {
265
        return strtr($template, [
266
            '{service}' => $service,
267
            '{region}' => $region,
268
            '{dnsSuffix}' => $dnsSuffix,
269
        ]);
270
    }
271
 
272
    /**
273
     * @param $region
274
     * @return bool
275
     */
276
    private function isFipsEndpointUsed($region)
277
    {
278
        return strpos($region, "fips") !== false;
279
    }
280
 
281
    /**
282
     * @param array $options
283
     * @param array $data
284
     * @return array
285
     */
286
    private function getVariant(array $options, array $data)
287
    {
288
        $variantTags = [];
289
        if (isset($options['use_fips_endpoint'])) {
290
            $useFips = $options['use_fips_endpoint'];
291
            if (is_bool($useFips)) {
292
                $useFips && $variantTags[] = 'fips';
293
            } elseif ($useFips->isUseFipsEndpoint()) {
294
                $variantTags[] = 'fips';
295
            }
296
        }
297
        if (isset($options['use_dual_stack_endpoint'])) {
298
            $useDualStack = $options['use_dual_stack_endpoint'];
299
            if (is_bool($useDualStack)) {
300
                $useDualStack && $variantTags[] = 'dualstack';
301
            } elseif ($useDualStack->isUseDualStackEndpoint()) {
302
                $variantTags[] = 'dualstack';
303
            }
304
        }
305
        if (!empty($variantTags)) {
306
            if (isset($data['variants'])) {
307
                foreach ($data['variants'] as $variant) {
308
                    if (array_count_values($variant['tags']) == array_count_values($variantTags)) {
309
                        return $variant;
310
                    }
311
                }
312
            }
313
            if (isset($this->data['defaults']['variants'])) {
314
                foreach ($this->data['defaults']['variants'] as $variant) {
315
                    if (array_count_values($variant['tags']) == array_count_values($variantTags)) {
316
                        return $variant;
317
                    }
318
                }
319
            }
320
        }
321
    }
322
}