PluginProbe
Media Cloud Sync / 1.4.1
Media Cloud Sync v1.4.1
1.4.1 1.4.0 1.3.12 1.3.11 1.3.10 trunk 1.0.0 1.0.1 1.0.2 1.0.3 1.1.0 1.1.1 1.2.0 1.2.10 1.2.11 1.2.12 1.2.13 1.2.2 1.2.3 1.2.4 1.2.5 1.2.6 1.2.7 1.2.8 1.2.9 All 35 releases
← All changes | includes/sdk/s3/Aws/AwsClient.php +267 -31 1.2.3 → 1.4.1 View file →
@@ -4,14 +4,17 @@
4 4
5 5 use Dudlewebs\WPMCS\s3\Aws\Api\ApiProvider;
6 6 use Dudlewebs\WPMCS\s3\Aws\Api\DocModel;
7 7 use Dudlewebs\WPMCS\s3\Aws\Api\Service;
8 -use Dudlewebs\WPMCS\s3\Aws\ClientSideMonitoring\ApiCallAttemptMonitoringMiddleware;
9 -use Dudlewebs\WPMCS\s3\Aws\ClientSideMonitoring\ApiCallMonitoringMiddleware;
10 -use Dudlewebs\WPMCS\s3\Aws\ClientSideMonitoring\ConfigurationProvider;
8 +use Dudlewebs\WPMCS\s3\Aws\Auth\AuthSelectionMiddleware;
9 +use Dudlewebs\WPMCS\s3\Aws\Auth\AuthSchemeResolverInterface;
11 10 use Dudlewebs\WPMCS\s3\Aws\EndpointDiscovery\EndpointDiscoveryMiddleware;
11 +use Dudlewebs\WPMCS\s3\Aws\EndpointV2\EndpointProviderV2;
12 +use Dudlewebs\WPMCS\s3\Aws\EndpointV2\EndpointV2Middleware;
13 +use Dudlewebs\WPMCS\s3\Aws\Exception\AwsException;
12 14 use Dudlewebs\WPMCS\s3\Aws\Signature\SignatureProvider;
13 15 use Dudlewebs\WPMCS\s3\GuzzleHttp\Psr7\Uri;
16 +use Dudlewebs\WPMCS\s3\Psr\Http\Message\RequestInterface;
14 17 /**
15 18 * Default AWS client implementation
16 19 */
17 20 class AwsClient implements AwsClientInterface
@@ -23,19 +26,33 @@
23 26 private $config;
24 27 /** @var string */
25 28 private $region;
26 29 /** @var string */
30 + private $signingRegionSet;
31 + /** @var string */
27 32 private $endpoint;
28 33 /** @var Service */
29 34 private $api;
30 35 /** @var callable */
31 36 private $signatureProvider;
37 + /** @var AuthSchemeResolverInterface */
38 + private $authSchemeResolver;
32 39 /** @var callable */
33 40 private $credentialProvider;
41 + /** @var callable */
42 + private $tokenProvider;
34 43 /** @var HandlerList */
35 44 private $handlerList;
36 45 /** @var array*/
37 46 private $defaultRequestOptions;
47 + /** @var array*/
48 + private $clientContextParams = [];
49 + /** @var array*/
50 + protected $clientBuiltIns = [];
51 + /** @var EndpointProviderV2 | callable */
52 + protected $endpointProvider;
53 + /** @var callable */
54 + protected $serializer;
38 55 /**
39 56 * Get an array of client constructor arguments used by the client.
40 57 *
41 58 * @return array
@@ -59,8 +76,17 @@
59 76 * credentials, or a callable credentials provider used to create
60 77 * credentials or return null. See Aws\Credentials\CredentialProvider for
61 78 * a list of built-in credentials providers. If no credentials are
62 79 * provided, the SDK will attempt to load them from the environment.
80 + * - token:
81 + * (Aws\Token\TokenInterface|array|bool|callable) Specifies
82 + * the token used to authorize requests. Provide an
83 + * Aws\Token\TokenInterface object, an associative array of
84 + * "token" and an optional "expires" key, `false` to use no
85 + * token, or a callable token provider used to create a
86 + * token or return null. See Aws\Token\TokenProvider for
87 + * a list of built-in token providers. If no token is
88 + * provided, the SDK will attempt to load one from the environment.
63 89 * - csm:
64 90 * (Aws\ClientSideMonitoring\ConfigurationInterface|array|callable) Specifies
65 91 * the credentials used to sign requests. Provide an
66 92 * Aws\ClientSideMonitoring\ConfigurationInterface object, a callable
@@ -167,8 +193,25 @@
167 193 * - validate: (bool, default=bool(true)) Set to false to disable
168 194 * client-side parameter validation.
169 195 * - version: (string, required) The version of the webservice to
170 196 * utilize (e.g., 2006-03-01).
197 + * - account_id_endpoint_mode: (string, default(preferred)) this option
198 + * decides whether credentials should resolve an accountId value,
199 + * which is going to be used as part of the endpoint resolution.
200 + * The valid values for this option are:
201 + * - preferred: when this value is set then, a warning is logged when
202 + * accountId is empty in the resolved identity.
203 + * - required: when this value is set then, an exception is thrown when
204 + * accountId is empty in the resolved identity.
205 + * - disabled: when this value is set then, the validation for if accountId
206 + * was resolved or not, is ignored.
207 + * - ua_append: (string, array) To pass custom user agent parameters.
208 + * - app_id: (string) an optional application specific identifier that can be set.
209 + * When set it will be appended to the User-Agent header of every request
210 + * in the form of App/{AppId}. This variable is sourced from environment
211 + * variable AWS_SDK_UA_APP_ID or the shared config profile attribute sdk_ua_app_id.
212 + * See https://docs.aws.amazon.com/sdkref/latest/guide/settings-reference.html for
213 + * more information on environment variables and shared config settings.
171 214 *
172 215 * @param array $args Client configuration arguments.
173 216 *
174 217 * @throws \InvalidArgumentException if any required options are missing or
@@ -187,23 +230,40 @@
187 230 $resolver = new ClientResolver(static::getArguments());
188 231 $config = $resolver->resolve($args, $this->handlerList);
189 232 $this->api = $config['api'];
190 233 $this->signatureProvider = $config['signature_provider'];
234 + $this->authSchemeResolver = $config['auth_scheme_resolver'];
191 235 $this->endpoint = new Uri($config['endpoint']);
192 236 $this->credentialProvider = $config['credentials'];
193 - $this->region = isset($config['region']) ? $config['region'] : null;
237 + $this->tokenProvider = $config['token'];
238 + $this->region = $config['region'] ?? null;
239 + $this->signingRegionSet = $config['sigv4a_signing_region_set'] ?? null;
194 240 $this->config = $config['config'];
241 + $this->setClientBuiltIns($args, $config);
242 + $this->clientContextParams = $this->setClientContextParams($args);
195 243 $this->defaultRequestOptions = $config['http'];
196 - $this->addSignatureMiddleware();
244 + $this->endpointProvider = $config['endpoint_provider'];
245 + $this->serializer = $config['serializer'];
246 + $this->addSignatureMiddleware($args);
197 247 $this->addInvocationId();
198 248 $this->addEndpointParameterMiddleware($args);
199 249 $this->addEndpointDiscoveryMiddleware($config, $args);
250 + $this->addRequestCompressionMiddleware($config);
200 251 $this->loadAliases();
201 252 $this->addStreamRequestPayload();
202 253 $this->addRecursionDetection();
254 + if ($this->isUseEndpointV2()) {
255 + $this->addEndpointV2Middleware();
256 + }
257 + $this->addAuthSelectionMiddleware($config['config']);
258 + if (!\is_null($this->api->getMetadata('awsQueryCompatible'))) {
259 + $this->addQueryCompatibleInputMiddleware($this->api);
260 + $this->addQueryModeHeader();
261 + }
203 262 if (isset($args['with_resolved'])) {
204 263 $args['with_resolved']($config);
205 264 }
265 + $this->addUserAgentMiddleware($config);
206 266 }
207 267 public function getHandlerList()
208 268 {
209 269 return $this->handlerList;
@@ -209,9 +269,9 @@
209 269 return $this->handlerList;
210 270 }
211 271 public function getConfig($option = null)
212 272 {
213 - return $option === null ? $this->config : (isset($this->config[$option]) ? $this->config[$option] : null);
273 + return $option === null ? $this->config : $this->config[$option] ?? null;
214 274 }
215 275 public function getCredentials()
216 276 {
217 277 $fn = $this->credentialProvider;
@@ -216,8 +276,13 @@
216 276 {
217 277 $fn = $this->credentialProvider;
218 278 return $fn();
219 279 }
280 + public function getToken()
281 + {
282 + $fn = $this->tokenProvider;
283 + return $fn();
284 + }
220 285 public function getEndpoint()
221 286 {
222 287 return $this->endpoint;
223 288 }
@@ -244,8 +309,32 @@
244 309 $args['@http'] += $this->defaultRequestOptions;
245 310 }
246 311 return new Command($name, $args, clone $this->getHandlerList());
247 312 }
313 + public function getEndpointProvider()
314 + {
315 + return $this->endpointProvider;
316 + }
317 + /**
318 + * Provides the set of service context parameter
319 + * key-value pairs used for endpoint resolution.
320 + *
321 + * @return array
322 + */
323 + public function getClientContextParams()
324 + {
325 + return $this->clientContextParams;
326 + }
327 + /**
328 + * Provides the set of built-in keys and values
329 + * used for endpoint resolution
330 + *
331 + * @return array
332 + */
333 + public function getClientBuiltIns()
334 + {
335 + return $this->clientBuiltIns;
336 + }
248 337 public function __sleep()
249 338 {
250 339 throw new \RuntimeException('Instances of ' . static::class . ' cannot be serialized');
251 340 }
@@ -267,9 +356,9 @@
267 356 private function parseClass()
268 357 {
269 358 $klass = \get_class($this);
270 359 if ($klass === __CLASS__) {
271 - return ['', 'Dudlewebs\\WPMCS\\s3\\Aws\\Exception\\AwsException'];
360 + return ['', AwsException::class];
272 361 }
273 362 $service = \substr($klass, \strrpos($klass, '\\') + 1, -6);
274 363 return [\strtolower($service), "Dudlewebs\\WPMCS\\s3\\Aws\\{$service}\\Exception\\{$service}Exception"];
275 364 }
@@ -286,40 +375,74 @@
286 375 if (!isset($args['endpoint'])) {
287 376 $list->appendBuild(EndpointDiscoveryMiddleware::wrap($this, $args, $config['endpoint_discovery']), 'EndpointDiscoveryMiddleware');
288 377 }
289 378 }
290 - private function addSignatureMiddleware()
379 + private function addSignatureMiddleware(array $args)
291 380 {
292 381 $api = $this->getApi();
293 382 $provider = $this->signatureProvider;
294 - $version = $this->config['signature_version'];
383 + $signatureVersion = $this->config['signature_version'];
295 384 $name = $this->config['signing_name'];
296 385 $region = $this->config['signing_region'];
297 - $resolver = static function (CommandInterface $c) use($api, $provider, $name, $region, $version) {
298 - if (!empty($c['@context']['signing_region'])) {
299 - $region = $c['@context']['signing_region'];
386 + $signingRegionSet = $this->signingRegionSet;
387 + if (isset($args['signature_version']) || isset($this->config['configured_signature_version'])) {
388 + $configuredSignatureVersion = \true;
389 + } else {
390 + $configuredSignatureVersion = \false;
391 + }
392 + $resolver = static function (CommandInterface $command) use($api, $provider, $name, $region, $signatureVersion, $configuredSignatureVersion, $signingRegionSet) {
393 + if (!$configuredSignatureVersion) {
394 + if (!empty($command['@context']['signing_region'])) {
395 + $region = $command['@context']['signing_region'];
396 + }
397 + if (!empty($command['@context']['signing_service'])) {
398 + $name = $command['@context']['signing_service'];
399 + }
400 + if (!empty($command['@context']['signature_version'])) {
401 + $signatureVersion = $command['@context']['signature_version'];
402 + }
403 + $authType = $api->getOperation($command->getName())['authtype'];
404 + switch ($authType) {
405 + case 'none':
406 + $signatureVersion = 'anonymous';
407 + break;
408 + case 'v4-unsigned-body':
409 + $signatureVersion = 'v4-unsigned-body';
410 + break;
411 + case 'bearer':
412 + $signatureVersion = 'bearer';
413 + break;
414 + }
300 415 }
301 - if (!empty($c['@context']['signing_service'])) {
302 - $name = $c['@context']['signing_service'];
416 + if ($signatureVersion === 'v4a') {
417 + $commandSigningRegionSet = !empty($command['@context']['signing_region_set']) ? \implode(', ', $command['@context']['signing_region_set']) : null;
418 + $region = $signingRegionSet ?? $commandSigningRegionSet ?? $region;
303 419 }
304 - $authType = $api->getOperation($c->getName())['authtype'];
305 - switch ($authType) {
306 - case 'none':
307 - $version = 'anonymous';
308 - break;
309 - case 'v4-unsigned-body':
310 - $version = 'v4-unsigned-body';
311 - break;
312 - }
313 - if (isset($c['@context']['signature_version'])) {
314 - if ($c['@context']['signature_version'] == 'v4a') {
315 - $version = 'v4a';
316 - }
317 - }
318 - return SignatureProvider::resolve($provider, $version, $name, $region);
420 + // Capture signature metric
421 + $command->getMetricsBuilder()->identifyMetricByValueAndAppend('signature', $signatureVersion);
422 + return SignatureProvider::resolve($provider, $signatureVersion, $name, $region);
319 423 };
320 - $this->handlerList->appendSign(Middleware::signer($this->credentialProvider, $resolver), 'signer');
424 + $this->handlerList->appendSign(Middleware::signer($this->credentialProvider, $resolver, $this->tokenProvider, $this->getConfig()), 'signer');
321 425 }
426 + private function addRequestCompressionMiddleware($config)
427 + {
428 + if (empty($config['disable_request_compression'])) {
429 + $list = $this->getHandlerList();
430 + $list->appendBuild(RequestCompressionMiddleware::wrap($config), 'request-compression');
431 + }
432 + }
433 + private function addQueryCompatibleInputMiddleware(Service $api)
434 + {
435 + $list = $this->getHandlerList();
436 + $list->appendValidate(QueryCompatibleInputMiddleware::wrap($api), 'query-compatible-input');
437 + }
438 + private function addQueryModeHeader() : void
439 + {
440 + $list = $this->getHandlerList();
441 + $list->appendBuild(Middleware::mapRequest(function (RequestInterface $r) {
442 + return $r->withHeader('x-amzn-query-mode', "true");
443 + }), 'x-amzn-query-mode-header');
444 + }
322 445 private function addInvocationId()
323 446 {
324 447 // Add invocation id to each request
325 448 $this->handlerList->prependSign(Middleware::invocationId(), 'invocation-id');
@@ -348,9 +471,122 @@
348 471 // Add recursion detection header to requests
349 472 // originating in supported Lambda runtimes
350 473 $this->handlerList->appendBuild(Middleware::recursionDetection(), 'recursion-detection');
351 474 }
475 + private function addAuthSelectionMiddleware(array $args)
476 + {
477 + $list = $this->getHandlerList();
478 + $list->prependBuild(AuthSelectionMiddleware::wrap($this->authSchemeResolver, $this->getApi(), $args['auth_scheme_preference'] ?? null), 'auth-selection');
479 + }
480 + private function addEndpointV2Middleware()
481 + {
482 + $list = $this->getHandlerList();
483 + $endpointArgs = $this->getEndpointProviderArgs();
484 + $list->prependBuild(EndpointV2Middleware::wrap($this->endpointProvider, $this->getApi(), $endpointArgs, $this->credentialProvider), 'endpoint-resolution');
485 + }
352 486 /**
487 + * Appends the user agent middleware.
488 + * This middleware MUST be appended after the
489 + * signature middleware `addSignatureMiddleware`,
490 + * so that metrics around signatures are properly
491 + * captured.
492 + *
493 + * @param $args
494 + * @return void
495 + */
496 + private function addUserAgentMiddleware($args)
497 + {
498 + $this->getHandlerList()->appendSign(UserAgentMiddleware::wrap($args), 'user-agent');
499 + }
500 + /**
501 + * Retrieves client context param definition from service model,
502 + * creates mapping of client context param names with client-provided
503 + * values.
504 + *
505 + * @return array
506 + */
507 + private function setClientContextParams($args)
508 + {
509 + $api = $this->getApi();
510 + $resolvedParams = [];
511 + if (!empty($paramDefinitions = $api->getClientContextParams())) {
512 + foreach ($paramDefinitions as $paramName => $paramValue) {
513 + if (isset($args[$paramName])) {
514 + $resolvedParams[$paramName] = $args[$paramName];
515 + }
516 + }
517 + }
518 + return $resolvedParams;
519 + }
520 + /**
521 + * Retrieves and sets default values used for endpoint resolution.
522 + */
523 + private function setClientBuiltIns($args, $resolvedConfig)
524 + {
525 + $builtIns = [];
526 + $config = $resolvedConfig['config'];
527 + $service = $args['service'];
528 + $builtIns['SDK::Endpoint'] = null;
529 + if (!empty($args['endpoint'])) {
530 + $builtIns['SDK::Endpoint'] = $args['endpoint'];
531 + } elseif (isset($config['configured_endpoint_url'])) {
532 + $builtIns['SDK::Endpoint'] = (string) $this->getEndpoint();
533 + }
534 + $builtIns['AWS::Region'] = $this->getRegion();
535 + $builtIns['AWS::UseFIPS'] = $config['use_fips_endpoint']->isUseFipsEndpoint();
536 + $builtIns['AWS::UseDualStack'] = $config['use_dual_stack_endpoint']->isUseDualstackEndpoint();
537 + if ($service === 's3' || $service === 's3control') {
538 + $builtIns['AWS::S3::UseArnRegion'] = $config['use_arn_region']->isUseArnRegion();
539 + }
540 + if ($service === 's3') {
541 + $builtIns['AWS::S3::UseArnRegion'] = $config['use_arn_region']->isUseArnRegion();
542 + $builtIns['AWS::S3::Accelerate'] = $config['use_accelerate_endpoint'];
543 + $builtIns['AWS::S3::ForcePathStyle'] = $config['use_path_style_endpoint'];
544 + $builtIns['AWS::S3::DisableMultiRegionAccessPoints'] = $config['disable_multiregion_access_points'];
545 + }
546 + $builtIns['AWS::Auth::AccountIdEndpointMode'] = $resolvedConfig['account_id_endpoint_mode'];
547 + $this->clientBuiltIns += $builtIns;
548 + }
549 + /**
550 + * Retrieves arguments to be used in endpoint resolution.
551 + *
552 + * @return array
553 + */
554 + public function getEndpointProviderArgs()
555 + {
556 + return $this->normalizeEndpointProviderArgs();
557 + }
558 + /**
559 + * Combines built-in and client context parameter values in
560 + * order of specificity. Client context parameter values supersede
561 + * built-in values.
562 + *
563 + * @return array
564 + */
565 + private function normalizeEndpointProviderArgs()
566 + {
567 + $normalizedBuiltIns = [];
568 + foreach ($this->clientBuiltIns as $name => $value) {
569 + $normalizedName = \explode('::', $name);
570 + $normalizedName = $normalizedName[\count($normalizedName) - 1];
571 + $normalizedBuiltIns[$normalizedName] = $value;
572 + }
573 + return \array_merge($normalizedBuiltIns, $this->getClientContextParams());
574 + }
575 + protected function isUseEndpointV2()
576 + {
577 + return $this->endpointProvider instanceof EndpointProviderV2;
578 + }
579 + public static function emitDeprecationWarning()
580 + {
581 + \trigger_error("This method is deprecated. It will be removed in an upcoming release.", \E_USER_DEPRECATED);
582 + $phpVersion = \PHP_VERSION_ID;
583 + if ($phpVersion < 70205) {
584 + $phpVersionString = \phpversion();
585 + @\trigger_error("This installation of the SDK is using PHP version" . " {$phpVersionString}, which will be deprecated on August" . " 15th, 2023. Please upgrade your PHP version to a minimum of" . " 7.2.5 before then to continue receiving updates to the AWS" . " SDK for PHP. To disable this warning, set" . " suppress_php_deprecation_warning to true on the client constructor" . " or set the environment variable AWS_SUPPRESS_PHP_DEPRECATION_WARNING" . " to true.", \E_USER_DEPRECATED);
586 + }
587 + }
588 + /**
353 589 * Returns a service model and doc model with any necessary changes
354 590 * applied.
355 591 *
356 592 * @param array $api Array of service data being documented.
@@ -363,9 +599,9 @@
363 599 */
364 600 public static function applyDocFilters(array $api, array $docs)
365 601 {
366 602 $aliases = \Dudlewebs\WPMCS\s3\Aws\load_compiled_json(__DIR__ . '/data/aliases.json');
367 - $serviceId = $api['metadata']['serviceId'];
603 + $serviceId = $api['metadata']['serviceId'] ?? '';
368 604 $version = $api['metadata']['apiVersion'];
369 605 // Replace names for any operations with SDK aliases
370 606 if (!empty($aliases['operations'][$serviceId][$version])) {
371 607 foreach ($aliases['operations'][$serviceId][$version] as $op => $alias) {