123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325 |
- <?php
- namespace Aws\EndpointV2;
- use Aws\Api\Operation;
- use Aws\Api\Service;
- use Aws\Auth\Exception\UnresolvedAuthSchemeException;
- use Aws\CommandInterface;
- use Closure;
- use GuzzleHttp\Promise\Promise;
- /**
- * Handles endpoint rule evaluation and endpoint resolution.
- *
- * IMPORTANT: this middleware must be added to the "build" step.
- * Specifically, it must precede the 'builder' step.
- *
- * @internal
- */
- class EndpointV2Middleware
- {
- private static $validAuthSchemes = [
- 'sigv4' => 'v4',
- 'sigv4a' => 'v4a',
- 'none' => 'anonymous',
- 'bearer' => 'bearer',
- 'sigv4-s3express' => 'v4-s3express'
- ];
- /** @var callable */
- private $nextHandler;
- /** @var EndpointProviderV2 */
- private $endpointProvider;
- /** @var Service */
- private $api;
- /** @var array */
- private $clientArgs;
- /**
- * Create a middleware wrapper function
- *
- * @param EndpointProviderV2 $endpointProvider
- * @param Service $api
- * @param array $args
- *
- * @return Closure
- */
- public static function wrap(
- EndpointProviderV2 $endpointProvider,
- Service $api,
- array $args
- ): Closure
- {
- return function (callable $handler) use ($endpointProvider, $api, $args) {
- return new self($handler, $endpointProvider, $api, $args);
- };
- }
- /**
- * @param callable $nextHandler
- * @param EndpointProviderV2 $endpointProvider
- * @param Service $api
- * @param array $args
- */
- public function __construct(
- callable $nextHandler,
- EndpointProviderV2 $endpointProvider,
- Service $api,
- array $args
- )
- {
- $this->nextHandler = $nextHandler;
- $this->endpointProvider = $endpointProvider;
- $this->api = $api;
- $this->clientArgs = $args;
- }
- /**
- * @param CommandInterface $command
- *
- * @return Promise
- */
- public function __invoke(CommandInterface $command)
- {
- $nextHandler = $this->nextHandler;
- $operation = $this->api->getOperation($command->getName());
- $commandArgs = $command->toArray();
- $providerArgs = $this->resolveArgs($commandArgs, $operation);
- $endpoint = $this->endpointProvider->resolveEndpoint($providerArgs);
- if (!empty($authSchemes = $endpoint->getProperty('authSchemes'))) {
- $this->applyAuthScheme(
- $authSchemes,
- $command
- );
- }
- return $nextHandler($command, $endpoint);
- }
- /**
- * Resolves client, context params, static context params and endpoint provider
- * arguments provided at the command level.
- *
- * @param array $commandArgs
- * @param Operation $operation
- *
- * @return array
- */
- private function resolveArgs(array $commandArgs, Operation $operation): array
- {
- $rulesetParams = $this->endpointProvider->getRuleset()->getParameters();
- $endpointCommandArgs = $this->filterEndpointCommandArgs(
- $rulesetParams,
- $commandArgs
- );
- $staticContextParams = $this->bindStaticContextParams(
- $operation->getStaticContextParams()
- );
- $contextParams = $this->bindContextParams(
- $commandArgs, $operation->getContextParams()
- );
- return array_merge(
- $this->clientArgs,
- $contextParams,
- $staticContextParams,
- $endpointCommandArgs
- );
- }
- /**
- * Compares Ruleset parameters against Command arguments
- * to create a mapping of arguments to pass into the
- * endpoint provider for endpoint resolution.
- *
- * @param array $rulesetParams
- * @param array $commandArgs
- * @return array
- */
- private function filterEndpointCommandArgs(
- array $rulesetParams,
- array $commandArgs
- ): array
- {
- $endpointMiddlewareOpts = [
- '@use_dual_stack_endpoint' => 'UseDualStack',
- '@use_accelerate_endpoint' => 'Accelerate',
- '@use_path_style_endpoint' => 'ForcePathStyle'
- ];
- $filteredArgs = [];
- foreach($rulesetParams as $name => $value) {
- if (isset($commandArgs[$name])) {
- if (!empty($value->getBuiltIn())) {
- continue;
- }
- $filteredArgs[$name] = $commandArgs[$name];
- }
- }
- if ($this->api->getServiceName() === 's3') {
- foreach($endpointMiddlewareOpts as $optionName => $newValue) {
- if (isset($commandArgs[$optionName])) {
- $filteredArgs[$newValue] = $commandArgs[$optionName];
- }
- }
- }
- return $filteredArgs;
- }
- /**
- * Binds static context params to their corresponding values.
- *
- * @param $staticContextParams
- *
- * @return array
- */
- private function bindStaticContextParams($staticContextParams): array
- {
- $scopedParams = [];
- forEach($staticContextParams as $paramName => $paramValue) {
- $scopedParams[$paramName] = $paramValue['value'];
- }
- return $scopedParams;
- }
- /**
- * Binds context params to their corresponding values found in
- * command arguments.
- *
- * @param array $commandArgs
- * @param array $contextParams
- *
- * @return array
- */
- private function bindContextParams(
- array $commandArgs,
- array $contextParams
- ): array
- {
- $scopedParams = [];
- foreach($contextParams as $name => $spec) {
- if (isset($commandArgs[$spec['shape']])) {
- $scopedParams[$name] = $commandArgs[$spec['shape']];
- }
- }
- return $scopedParams;
- }
- /**
- * Applies resolved auth schemes to the command object.
- *
- * @param $authSchemes
- * @param $command
- *
- * @return void
- */
- private function applyAuthScheme(
- array $authSchemes,
- CommandInterface $command
- ): void
- {
- $authScheme = $this->resolveAuthScheme($authSchemes);
- $command['@context']['signature_version'] = $authScheme['version'];
- if (isset($authScheme['name'])) {
- $command['@context']['signing_service'] = $authScheme['name'];
- }
- if (isset($authScheme['region'])) {
- $command['@context']['signing_region'] = $authScheme['region'];
- } elseif (isset($authScheme['signingRegionSet'])) {
- $command['@context']['signing_region_set'] = $authScheme['signingRegionSet'];
- }
- }
- /**
- * Returns the first compatible auth scheme in an endpoint object's
- * auth schemes.
- *
- * @param array $authSchemes
- *
- * @return array
- */
- private function resolveAuthScheme(array $authSchemes): array
- {
- $invalidAuthSchemes = [];
- foreach($authSchemes as $authScheme) {
- if ($this->isValidAuthScheme($authScheme['name'])) {
- return $this->normalizeAuthScheme($authScheme);
- }
- $invalidAuthSchemes[$authScheme['name']] = false;
- }
- $invalidAuthSchemesString = '`' . implode(
- '`, `',
- array_keys($invalidAuthSchemes))
- . '`';
- $validAuthSchemesString = '`'
- . implode('`, `', array_keys(
- array_diff_key(self::$validAuthSchemes, $invalidAuthSchemes))
- )
- . '`';
- throw new UnresolvedAuthSchemeException(
- "This operation requests {$invalidAuthSchemesString}"
- . " auth schemes, but the client currently supports {$validAuthSchemesString}."
- );
- }
- /**
- * Normalizes an auth scheme's name, signing region or signing region set
- * to the auth keys recognized by the SDK.
- *
- * @param array $authScheme
- * @return array
- */
- private function normalizeAuthScheme(array $authScheme): array
- {
- /*
- sigv4a will contain a regionSet property. which is guaranteed to be `*`
- for now. The SigV4 class handles this automatically for now. It seems
- complexity will be added here in the future.
- */
- $normalizedAuthScheme = [];
- if (isset($authScheme['disableDoubleEncoding'])
- && $authScheme['disableDoubleEncoding'] === true
- && $authScheme['name'] !== 'sigv4a'
- && $authScheme['name'] !== 'sigv4-s3express'
- ) {
- $normalizedAuthScheme['version'] = 's3v4';
- } else {
- $normalizedAuthScheme['version'] = self::$validAuthSchemes[$authScheme['name']];
- }
- $normalizedAuthScheme['name'] = $authScheme['signingName'] ?? null;
- $normalizedAuthScheme['region'] = $authScheme['signingRegion'] ?? null;
- $normalizedAuthScheme['signingRegionSet'] = $authScheme['signingRegionSet'] ?? null;
- return $normalizedAuthScheme;
- }
- private function isValidAuthScheme($signatureVersion): bool
- {
- if (isset(self::$validAuthSchemes[$signatureVersion])) {
- if ($signatureVersion === 'sigv4a') {
- return extension_loaded('awscrt');
- }
- return true;
- }
- return false;
- }
- }
|