diff options
author | Andrew Dolgov <[email protected]> | 2022-11-23 21:14:33 +0300 |
---|---|---|
committer | Andrew Dolgov <[email protected]> | 2022-11-23 21:14:33 +0300 |
commit | 0c8af4992cb0f7589dcafaad65ada12753c64594 (patch) | |
tree | 18e83d068c3e7dd2499331de977782b382279396 /vendor/aws/aws-sdk-php/src/S3/BucketEndpointArnMiddleware.php |
initial
Diffstat (limited to 'vendor/aws/aws-sdk-php/src/S3/BucketEndpointArnMiddleware.php')
-rw-r--r-- | vendor/aws/aws-sdk-php/src/S3/BucketEndpointArnMiddleware.php | 355 |
1 files changed, 355 insertions, 0 deletions
diff --git a/vendor/aws/aws-sdk-php/src/S3/BucketEndpointArnMiddleware.php b/vendor/aws/aws-sdk-php/src/S3/BucketEndpointArnMiddleware.php new file mode 100644 index 0000000..becfded --- /dev/null +++ b/vendor/aws/aws-sdk-php/src/S3/BucketEndpointArnMiddleware.php @@ -0,0 +1,355 @@ +<?php +namespace Aws\S3; + +use Aws\Api\Service; +use Aws\Arn\AccessPointArnInterface; +use Aws\Arn\ArnParser; +use Aws\Arn\ObjectLambdaAccessPointArn; +use Aws\Arn\Exception\InvalidArnException; +use Aws\Arn\AccessPointArn as BaseAccessPointArn; +use Aws\Arn\S3\OutpostsAccessPointArn; +use Aws\Arn\S3\MultiRegionAccessPointArn; +use Aws\Arn\S3\OutpostsArnInterface; +use Aws\CommandInterface; +use Aws\Endpoint\PartitionEndpointProvider; +use Aws\Exception\InvalidRegionException; +use Aws\Exception\UnresolvedEndpointException; +use Aws\S3\Exception\S3Exception; +use InvalidArgumentException; +use Psr\Http\Message\RequestInterface; + +/** + * Checks for access point ARN in members targeting BucketName, modifying + * endpoint as appropriate + * + * @internal + */ +class BucketEndpointArnMiddleware +{ + use EndpointRegionHelperTrait; + + /** @var callable */ + private $nextHandler; + + /** @var array */ + private $nonArnableCommands = ['CreateBucket']; + + /** @var boolean */ + private $isUseEndpointV2; + + /** + * Create a middleware wrapper function. + * + * @param Service $service + * @param $region + * @param array $config + * @return callable + */ + public static function wrap( + Service $service, + $region, + array $config, + $isUseEndpointV2 + ) { + return function (callable $handler) use ($service, $region, $config, $isUseEndpointV2) { + return new self($handler, $service, $region, $config, $isUseEndpointV2); + }; + } + + public function __construct( + callable $nextHandler, + Service $service, + $region, + array $config = [], + $isUseEndpointV2 = false + ) { + $this->partitionProvider = PartitionEndpointProvider::defaultProvider(); + $this->region = $region; + $this->service = $service; + $this->config = $config; + $this->nextHandler = $nextHandler; + $this->isUseEndpointV2 = $isUseEndpointV2; + } + + public function __invoke(CommandInterface $cmd, RequestInterface $req) + { + $nextHandler = $this->nextHandler; + + $op = $this->service->getOperation($cmd->getName())->toArray(); + if (!empty($op['input']['shape'])) { + $service = $this->service->toArray(); + if (!empty($input = $service['shapes'][$op['input']['shape']])) { + foreach ($input['members'] as $key => $member) { + if ($member['shape'] === 'BucketName') { + $arnableKey = $key; + break; + } + } + + if (!empty($arnableKey) && ArnParser::isArn($cmd[$arnableKey])) { + + try { + // Throw for commands that do not support ARN inputs + if (in_array($cmd->getName(), $this->nonArnableCommands)) { + throw new S3Exception( + 'ARN values cannot be used in the bucket field for' + . ' the ' . $cmd->getName() . ' operation.', + $cmd + ); + } + + if (!$this->isUseEndpointV2) { + $arn = ArnParser::parse($cmd[$arnableKey]); + $partition = $this->validateArn($arn); + $host = $this->generateAccessPointHost($arn, $req); + } + // Remove encoded bucket string from path + $path = $req->getUri()->getPath(); + $encoded = rawurlencode($cmd[$arnableKey]); + $len = strlen($encoded) + 1; + if (trim(substr($path, 0, $len), '/') === "{$encoded}") { + $path = substr($path, $len); + if (substr($path, 0, 1) !== "/") { + $path = '/' . $path; + } + } + if (empty($path)) { + $path = ''; + } + + // Set modified request + if ($this->isUseEndpointV2) { + $req = $req->withUri( + $req->getUri()->withPath($path) + + ); + goto next; + } + + $req = $req->withUri( + $req->getUri()->withPath($path)->withHost($host) + ); + + // Update signing region based on ARN data if configured to do so + if ($this->config['use_arn_region']->isUseArnRegion() + && !$this->config['use_fips_endpoint']->isUseFipsEndpoint() + ) { + $region = $arn->getRegion(); + } else { + $region = $this->region; + } + $endpointData = $partition([ + 'region' => $region, + 'service' => $arn->getService() + ]); + $cmd['@context']['signing_region'] = $endpointData['signingRegion']; + + // Update signing service for Outposts and Lambda ARNs + if ($arn instanceof OutpostsArnInterface + || $arn instanceof ObjectLambdaAccessPointArn + ) { + $cmd['@context']['signing_service'] = $arn->getService(); + } + } catch (InvalidArnException $e) { + // Add context to ARN exception + throw new S3Exception( + 'Bucket parameter parsed as ARN and failed with: ' + . $e->getMessage(), + $cmd, + [], + $e + ); + } + } + } + } + next: + return $nextHandler($cmd, $req); + } + + + private function generateAccessPointHost( + BaseAccessPointArn $arn, + RequestInterface $req + ) { + if ($arn instanceof OutpostsAccessPointArn) { + $accesspointName = $arn->getAccesspointName(); + } else { + $accesspointName = $arn->getResourceId(); + } + + if ($arn instanceof MultiRegionAccessPointArn) { + $partition = $this->partitionProvider->getPartitionByName( + $arn->getPartition(), + 's3' + ); + $dnsSuffix = $partition->getDnsSuffix(); + return "{$accesspointName}.accesspoint.s3-global.{$dnsSuffix}"; + } + + $host = "{$accesspointName}-" . $arn->getAccountId(); + + $useFips = $this->config['use_fips_endpoint']->isUseFipsEndpoint(); + $fipsString = $useFips ? "-fips" : ""; + + if ($arn instanceof OutpostsAccessPointArn) { + $host .= '.' . $arn->getOutpostId() . '.s3-outposts'; + } else if ($arn instanceof ObjectLambdaAccessPointArn) { + if (!empty($this->config['endpoint'])) { + return $host . '.' . $this->config['endpoint']; + } else { + $host .= ".s3-object-lambda{$fipsString}"; + } + } else { + $host .= ".s3-accesspoint{$fipsString}"; + if (!empty($this->config['dual_stack'])) { + $host .= '.dualstack'; + } + } + + if (!empty($this->config['use_arn_region']->isUseArnRegion())) { + $region = $arn->getRegion(); + } else { + $region = $this->region; + } + $region = \Aws\strip_fips_pseudo_regions($region); + $host .= '.' . $region . '.' . $this->getPartitionSuffix($arn, $this->partitionProvider); + return $host; + } + + /** + * Validates an ARN, returning a partition object corresponding to the ARN + * if successful + * + * @param $arn + * @return \Aws\Endpoint\Partition + */ + private function validateArn($arn) + { + if ($arn instanceof AccessPointArnInterface) { + + // Dualstack is not supported with Outposts access points + if ($arn instanceof OutpostsAccessPointArn + && !empty($this->config['dual_stack']) + ) { + throw new UnresolvedEndpointException( + 'Dualstack is currently not supported with S3 Outposts access' + . ' points. Please disable dualstack or do not supply an' + . ' access point ARN.'); + } + if ($arn instanceof MultiRegionAccessPointArn) { + if (!empty($this->config['disable_multiregion_access_points'])) { + throw new UnresolvedEndpointException( + 'Multi-Region Access Point ARNs are disabled, but one was provided. Please' + . ' enable them or provide a different ARN.' + ); + } + if (!empty($this->config['dual_stack'])) { + throw new UnresolvedEndpointException( + 'Multi-Region Access Point ARNs do not currently support dual stack. Please' + . ' disable dual stack or provide a different ARN.' + ); + } + } + // Accelerate is not supported with access points + if (!empty($this->config['accelerate'])) { + throw new UnresolvedEndpointException( + 'Accelerate is currently not supported with access points.' + . ' Please disable accelerate or do not supply an access' + . ' point ARN.'); + } + + // Path-style is not supported with access points + if (!empty($this->config['path_style'])) { + throw new UnresolvedEndpointException( + 'Path-style addressing is currently not supported with' + . ' access points. Please disable path-style or do not' + . ' supply an access point ARN.'); + } + + // Custom endpoint is not supported with access points + if (!is_null($this->config['endpoint']) + && !$arn instanceof ObjectLambdaAccessPointArn + ) { + throw new UnresolvedEndpointException( + 'A custom endpoint has been supplied along with an access' + . ' point ARN, and these are not compatible with each other.' + . ' Please only use one or the other.'); + } + + // Dualstack is not supported with object lambda access points + if ($arn instanceof ObjectLambdaAccessPointArn + && !empty($this->config['dual_stack']) + ) { + throw new UnresolvedEndpointException( + 'Dualstack is currently not supported with Object Lambda access' + . ' points. Please disable dualstack or do not supply an' + . ' access point ARN.'); + } + // Global endpoints do not support cross-region requests + if ($this->isGlobal($this->region) + && $this->config['use_arn_region']->isUseArnRegion() == false + && $arn->getRegion() != $this->region + && !$arn instanceof MultiRegionAccessPointArn + ) { + throw new UnresolvedEndpointException( + 'Global endpoints do not support cross region requests.' + . ' Please enable use_arn_region or do not supply a global region' + . ' with a different region in the ARN.'); + } + + // Get partitions for ARN and client region + $arnPart = $this->partitionProvider->getPartition( + $arn->getRegion(), + 's3' + ); + $clientPart = $this->partitionProvider->getPartition( + $this->region, + 's3' + ); + + // If client partition not found, try removing pseudo-region qualifiers + if (!($clientPart->isRegionMatch($this->region, 's3'))) { + $clientPart = $this->partitionProvider->getPartition( + \Aws\strip_fips_pseudo_regions($this->region), + 's3' + ); + } + if (!$arn instanceof MultiRegionAccessPointArn) { + // Verify that the partition matches for supplied partition and region + if ($arn->getPartition() !== $clientPart->getName()) { + throw new InvalidRegionException('The supplied ARN partition' + . " does not match the client's partition."); + } + if ($clientPart->getName() !== $arnPart->getName()) { + throw new InvalidRegionException('The corresponding partition' + . ' for the supplied ARN region does not match the' + . " client's partition."); + } + + // Ensure ARN region matches client region unless + // configured for using ARN region over client region + $this->validateMatchingRegion($arn); + + // Ensure it is not resolved to fips pseudo-region for S3 Outposts + $this->validateFipsConfigurations($arn); + } + + return $arnPart; + } + + throw new InvalidArnException('Provided ARN was not a valid S3 access' + . ' point ARN or S3 Outposts access point ARN.'); + } + + /** + * Checks if a region is global + * + * @param $region + * @return bool + */ + private function isGlobal($region) + { + return $region == 's3-external-1' || $region == 'aws-global'; + } +} |