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/Signature |
initial
Diffstat (limited to 'vendor/aws/aws-sdk-php/src/Signature')
6 files changed, 857 insertions, 0 deletions
diff --git a/vendor/aws/aws-sdk-php/src/Signature/AnonymousSignature.php b/vendor/aws/aws-sdk-php/src/Signature/AnonymousSignature.php new file mode 100644 index 0000000..9ccc8df --- /dev/null +++ b/vendor/aws/aws-sdk-php/src/Signature/AnonymousSignature.php @@ -0,0 +1,33 @@ +<?php +namespace Aws\Signature; + +use Aws\Credentials\CredentialsInterface; +use Psr\Http\Message\RequestInterface; + +/** + * Provides anonymous client access (does not sign requests). + */ +class AnonymousSignature implements SignatureInterface +{ + /** + * /** {@inheritdoc} + */ + public function signRequest( + RequestInterface $request, + CredentialsInterface $credentials + ) { + return $request; + } + + /** + * /** {@inheritdoc} + */ + public function presign( + RequestInterface $request, + CredentialsInterface $credentials, + $expires, + array $options = [] + ) { + return $request; + } +} diff --git a/vendor/aws/aws-sdk-php/src/Signature/S3SignatureV4.php b/vendor/aws/aws-sdk-php/src/Signature/S3SignatureV4.php new file mode 100644 index 0000000..e6ba30f --- /dev/null +++ b/vendor/aws/aws-sdk-php/src/Signature/S3SignatureV4.php @@ -0,0 +1,88 @@ +<?php +namespace Aws\Signature; + +use Aws\Credentials\CredentialsInterface; +use Psr\Http\Message\RequestInterface; + +/** + * Amazon S3 signature version 4 support. + */ +class S3SignatureV4 extends SignatureV4 +{ + /** + * S3-specific signing logic + * + * {@inheritdoc} + */ + use SignatureTrait; + + public function signRequest( + RequestInterface $request, + CredentialsInterface $credentials, + $signingService = null + ) { + // Always add a x-amz-content-sha-256 for data integrity + if (!$request->hasHeader('x-amz-content-sha256')) { + $request = $request->withHeader( + 'x-amz-content-sha256', + $this->getPayload($request) + ); + } + $useCrt = + strpos($request->getUri()->getHost(), "accesspoint.s3-global") + !== false; + if (!$useCrt) { + if (strpos($request->getUri()->getHost(), "s3-object-lambda")) { + return parent::signRequest($request, $credentials, "s3-object-lambda"); + } + return parent::signRequest($request, $credentials); + } + $signingService = $signingService ?: 's3'; + return $this->signWithV4a($credentials, $request, $signingService); + } + + /** + * Always add a x-amz-content-sha-256 for data integrity. + * + * {@inheritdoc} + */ + public function presign( + RequestInterface $request, + CredentialsInterface $credentials, + $expires, + array $options = [] + ) { + if (!$request->hasHeader('x-amz-content-sha256')) { + $request = $request->withHeader( + 'X-Amz-Content-Sha256', + $this->getPresignedPayload($request) + ); + } + if (strpos($request->getUri()->getHost(), "accesspoint.s3-global")) { + $request = $request->withHeader("x-amz-region-set", "*"); + } + + return parent::presign($request, $credentials, $expires, $options); + } + + /** + * Override used to allow pre-signed URLs to be created for an + * in-determinate request payload. + */ + protected function getPresignedPayload(RequestInterface $request) + { + return SignatureV4::UNSIGNED_PAYLOAD; + } + + /** + * Amazon S3 does not double-encode the path component in the canonical request + */ + protected function createCanonicalizedPath($path) + { + // Only remove one slash in case of keys that have a preceding slash + if (substr($path, 0, 1) === '/') { + $path = substr($path, 1); + } + return '/' . $path; + } +} diff --git a/vendor/aws/aws-sdk-php/src/Signature/SignatureInterface.php b/vendor/aws/aws-sdk-php/src/Signature/SignatureInterface.php new file mode 100644 index 0000000..cedfc45 --- /dev/null +++ b/vendor/aws/aws-sdk-php/src/Signature/SignatureInterface.php @@ -0,0 +1,45 @@ +<?php +namespace Aws\Signature; + +use Aws\Credentials\CredentialsInterface; +use Psr\Http\Message\RequestInterface; + +/** + * Interface used to provide interchangeable strategies for signing requests + * using the various AWS signature protocols. + */ +interface SignatureInterface +{ + /** + * Signs the specified request with an AWS signing protocol by using the + * provided AWS account credentials and adding the required headers to the + * request. + * + * @param RequestInterface $request Request to sign + * @param CredentialsInterface $credentials Signing credentials + * + * @return RequestInterface Returns the modified request. + */ + public function signRequest( + RequestInterface $request, + CredentialsInterface $credentials + ); + + /** + * Create a pre-signed request. + * + * @param RequestInterface $request Request to sign + * @param CredentialsInterface $credentials Credentials used to sign + * @param int|string|\DateTimeInterface $expires The time at which the URL should + * expire. This can be a Unix timestamp, a PHP DateTime object, or a + * string that can be evaluated by strtotime. + * + * @return RequestInterface + */ + public function presign( + RequestInterface $request, + CredentialsInterface $credentials, + $expires, + array $options = [] + ); +} diff --git a/vendor/aws/aws-sdk-php/src/Signature/SignatureProvider.php b/vendor/aws/aws-sdk-php/src/Signature/SignatureProvider.php new file mode 100644 index 0000000..d2ec4fd --- /dev/null +++ b/vendor/aws/aws-sdk-php/src/Signature/SignatureProvider.php @@ -0,0 +1,141 @@ +<?php +namespace Aws\Signature; + +use Aws\Exception\UnresolvedSignatureException; +use Aws\Token\BearerTokenAuthorization; + +/** + * Signature providers. + * + * A signature provider is a function that accepts a version, service, and + * region and returns a {@see SignatureInterface} object on success or NULL if + * no signature can be created from the provided arguments. + * + * You can wrap your calls to a signature provider with the + * {@see SignatureProvider::resolve} function to ensure that a signature object + * is created. If a signature object is not created, then the resolve() + * function will throw a {@see Aws\Exception\UnresolvedSignatureException}. + * + * use Aws\Signature\SignatureProvider; + * $provider = SignatureProvider::defaultProvider(); + * // Returns a SignatureInterface or NULL. + * $signer = $provider('v4', 's3', 'us-west-2'); + * // Returns a SignatureInterface or throws. + * $signer = SignatureProvider::resolve($provider, 'no', 's3', 'foo'); + * + * You can compose multiple providers into a single provider using + * {@see Aws\or_chain}. This function accepts providers as arguments and + * returns a new function that will invoke each provider until a non-null value + * is returned. + * + * $a = SignatureProvider::defaultProvider(); + * $b = function ($version, $service, $region) { + * if ($version === 'foo') { + * return new MyFooSignature(); + * } + * }; + * $c = \Aws\or_chain($a, $b); + * $signer = $c('v4', 'abc', '123'); // $a handles this. + * $signer = $c('foo', 'abc', '123'); // $b handles this. + * $nullValue = $c('???', 'abc', '123'); // Neither can handle this. + */ +class SignatureProvider +{ + private static $s3v4SignedServices = [ + 's3' => true, + 's3control' => true, + 's3-object-lambda' => true, + ]; + + /** + * Resolves and signature provider and ensures a non-null return value. + * + * @param callable $provider Provider function to invoke. + * @param string $version Signature version. + * @param string $service Service name. + * @param string $region Region name. + * + * @return SignatureInterface + * @throws UnresolvedSignatureException + */ + public static function resolve(callable $provider, $version, $service, $region) + { + $result = $provider($version, $service, $region); + if ($result instanceof SignatureInterface + || $result instanceof BearerTokenAuthorization + ) { + return $result; + } + + throw new UnresolvedSignatureException( + "Unable to resolve a signature for $version/$service/$region.\n" + . "Valid signature versions include v4 and anonymous." + ); + } + + /** + * Default SDK signature provider. + * + * @return callable + */ + public static function defaultProvider() + { + return self::memoize(self::version()); + } + + /** + * Creates a signature provider that caches previously created signature + * objects. The computed cache key is the concatenation of the version, + * service, and region. + * + * @param callable $provider Signature provider to wrap. + * + * @return callable + */ + public static function memoize(callable $provider) + { + $cache = []; + return function ($version, $service, $region) use (&$cache, $provider) { + $key = "($version)($service)($region)"; + if (!isset($cache[$key])) { + $cache[$key] = $provider($version, $service, $region); + } + return $cache[$key]; + }; + } + + /** + * Creates signature objects from known signature versions. + * + * This provider currently recognizes the following signature versions: + * + * - v4: Signature version 4. + * - anonymous: Does not sign requests. + * + * @return callable + */ + public static function version() + { + return function ($version, $service, $region) { + switch ($version) { + case 's3v4': + case 'v4': + return !empty(self::$s3v4SignedServices[$service]) + ? new S3SignatureV4($service, $region) + : new SignatureV4($service, $region); + case 'v4a': + return new SignatureV4($service, $region, ['use_v4a' => true]); + case 'v4-unsigned-body': + return !empty(self::$s3v4SignedServices[$service]) + ? new S3SignatureV4($service, $region, ['unsigned-body' => 'true']) + : new SignatureV4($service, $region, ['unsigned-body' => 'true']); + case 'bearer': + return new BearerTokenAuthorization(); + case 'anonymous': + return new AnonymousSignature(); + default: + return null; + } + }; + } +} diff --git a/vendor/aws/aws-sdk-php/src/Signature/SignatureTrait.php b/vendor/aws/aws-sdk-php/src/Signature/SignatureTrait.php new file mode 100644 index 0000000..5dcfe9d --- /dev/null +++ b/vendor/aws/aws-sdk-php/src/Signature/SignatureTrait.php @@ -0,0 +1,48 @@ +<?php +namespace Aws\Signature; + +/** + * Provides signature calculation for SignatureV4. + */ +trait SignatureTrait +{ + /** @var array Cache of previously signed values */ + private $cache = []; + + /** @var int Size of the hash cache */ + private $cacheSize = 0; + + private function createScope($shortDate, $region, $service) + { + return "$shortDate/$region/$service/aws4_request"; + } + + private function getSigningKey($shortDate, $region, $service, $secretKey) + { + $k = $shortDate . '_' . $region . '_' . $service . '_' . $secretKey; + + if (!isset($this->cache[$k])) { + // Clear the cache when it reaches 50 entries + if (++$this->cacheSize > 50) { + $this->cache = []; + $this->cacheSize = 0; + } + + $dateKey = hash_hmac( + 'sha256', + $shortDate, + "AWS4{$secretKey}", + true + ); + $regionKey = hash_hmac('sha256', $region, $dateKey, true); + $serviceKey = hash_hmac('sha256', $service, $regionKey, true); + $this->cache[$k] = hash_hmac( + 'sha256', + 'aws4_request', + $serviceKey, + true + ); + } + return $this->cache[$k]; + } +} diff --git a/vendor/aws/aws-sdk-php/src/Signature/SignatureV4.php b/vendor/aws/aws-sdk-php/src/Signature/SignatureV4.php new file mode 100644 index 0000000..4f93713 --- /dev/null +++ b/vendor/aws/aws-sdk-php/src/Signature/SignatureV4.php @@ -0,0 +1,502 @@ +<?php +namespace Aws\Signature; + +use Aws\Credentials\CredentialsInterface; +use AWS\CRT\Auth\Signable; +use AWS\CRT\Auth\SignatureType; +use AWS\CRT\Auth\Signing; +use AWS\CRT\Auth\SigningAlgorithm; +use AWS\CRT\Auth\SigningConfigAWS; +use AWS\CRT\Auth\StaticCredentialsProvider; +use AWS\CRT\HTTP\Request; +use Aws\Exception\CommonRuntimeException; +use Aws\Exception\CouldNotCreateChecksumException; +use GuzzleHttp\Psr7; +use Psr\Http\Message\RequestInterface; + +/** + * Signature Version 4 + * @link http://docs.aws.amazon.com/general/latest/gr/signature-version-4.html + */ +class SignatureV4 implements SignatureInterface +{ + use SignatureTrait; + const ISO8601_BASIC = 'Ymd\THis\Z'; + const UNSIGNED_PAYLOAD = 'UNSIGNED-PAYLOAD'; + const AMZ_CONTENT_SHA256_HEADER = 'X-Amz-Content-Sha256'; + + /** @var string */ + private $service; + + /** @var string */ + protected $region; + + /** @var bool */ + private $unsigned; + + /** @var bool */ + private $useV4a; + + /** + * The following headers are not signed because signing these headers + * would potentially cause a signature mismatch when sending a request + * through a proxy or if modified at the HTTP client level. + * + * @return array + */ + protected function getHeaderBlacklist() + { + return [ + 'cache-control' => true, + 'content-type' => true, + 'content-length' => true, + 'expect' => true, + 'max-forwards' => true, + 'pragma' => true, + 'range' => true, + 'te' => true, + 'if-match' => true, + 'if-none-match' => true, + 'if-modified-since' => true, + 'if-unmodified-since' => true, + 'if-range' => true, + 'accept' => true, + 'authorization' => true, + 'proxy-authorization' => true, + 'from' => true, + 'referer' => true, + 'user-agent' => true, + 'X-Amz-User-Agent' => true, + 'x-amzn-trace-id' => true, + 'aws-sdk-invocation-id' => true, + 'aws-sdk-retry' => true, + ]; + } + + /** + * @param string $service Service name to use when signing + * @param string $region Region name to use when signing + * @param array $options Array of configuration options used when signing + * - unsigned-body: Flag to make request have unsigned payload. + * Unsigned body is used primarily for streaming requests. + */ + public function __construct($service, $region, array $options = []) + { + $this->service = $service; + $this->region = $region; + $this->unsigned = isset($options['unsigned-body']) ? $options['unsigned-body'] : false; + $this->useV4a = isset($options['use_v4a']) && $options['use_v4a'] === true; + } + + /** + * {@inheritdoc} + */ + public function signRequest( + RequestInterface $request, + CredentialsInterface $credentials, + $signingService = null + ) { + $ldt = gmdate(self::ISO8601_BASIC); + $sdt = substr($ldt, 0, 8); + $parsed = $this->parseRequest($request); + $parsed['headers']['X-Amz-Date'] = [$ldt]; + + if ($token = $credentials->getSecurityToken()) { + $parsed['headers']['X-Amz-Security-Token'] = [$token]; + } + $service = isset($signingService) ? $signingService : $this->service; + + if ($this->useV4a) { + return $this->signWithV4a($credentials, $request, $service); + } + + $cs = $this->createScope($sdt, $this->region, $service); + $payload = $this->getPayload($request); + + if ($payload == self::UNSIGNED_PAYLOAD) { + $parsed['headers'][self::AMZ_CONTENT_SHA256_HEADER] = [$payload]; + } + + $context = $this->createContext($parsed, $payload); + $toSign = $this->createStringToSign($ldt, $cs, $context['creq']); + $signingKey = $this->getSigningKey( + $sdt, + $this->region, + $service, + $credentials->getSecretKey() + ); + $signature = hash_hmac('sha256', $toSign, $signingKey); + $parsed['headers']['Authorization'] = [ + "AWS4-HMAC-SHA256 " + . "Credential={$credentials->getAccessKeyId()}/{$cs}, " + . "SignedHeaders={$context['headers']}, Signature={$signature}" + ]; + + return $this->buildRequest($parsed); + } + + /** + * Get the headers that were used to pre-sign the request. + * Used for the X-Amz-SignedHeaders header. + * + * @param array $headers + * @return array + */ + private function getPresignHeaders(array $headers) + { + $presignHeaders = []; + $blacklist = $this->getHeaderBlacklist(); + foreach ($headers as $name => $value) { + $lName = strtolower($name); + if (!isset($blacklist[$lName]) + && $name !== self::AMZ_CONTENT_SHA256_HEADER + ) { + $presignHeaders[] = $lName; + } + } + return $presignHeaders; + } + + /** + * {@inheritdoc} + */ + public function presign( + RequestInterface $request, + CredentialsInterface $credentials, + $expires, + array $options = [] + ) { + + $startTimestamp = isset($options['start_time']) + ? $this->convertToTimestamp($options['start_time'], null) + : time(); + + $expiresTimestamp = $this->convertToTimestamp($expires, $startTimestamp); + + $parsed = $this->createPresignedRequest($request, $credentials); + $payload = $this->getPresignedPayload($request); + $httpDate = gmdate(self::ISO8601_BASIC, $startTimestamp); + $shortDate = substr($httpDate, 0, 8); + $scope = $this->createScope($shortDate, $this->region, $this->service); + $credential = $credentials->getAccessKeyId() . '/' . $scope; + if ($credentials->getSecurityToken()) { + unset($parsed['headers']['X-Amz-Security-Token']); + } + $parsed['query']['X-Amz-Algorithm'] = 'AWS4-HMAC-SHA256'; + $parsed['query']['X-Amz-Credential'] = $credential; + $parsed['query']['X-Amz-Date'] = gmdate('Ymd\THis\Z', $startTimestamp); + $parsed['query']['X-Amz-SignedHeaders'] = implode(';', $this->getPresignHeaders($parsed['headers'])); + $parsed['query']['X-Amz-Expires'] = $this->convertExpires($expiresTimestamp, $startTimestamp); + $context = $this->createContext($parsed, $payload); + $stringToSign = $this->createStringToSign($httpDate, $scope, $context['creq']); + $key = $this->getSigningKey( + $shortDate, + $this->region, + $this->service, + $credentials->getSecretKey() + ); + $parsed['query']['X-Amz-Signature'] = hash_hmac('sha256', $stringToSign, $key); + + return $this->buildRequest($parsed); + } + + /** + * Converts a POST request to a GET request by moving POST fields into the + * query string. + * + * Useful for pre-signing query protocol requests. + * + * @param RequestInterface $request Request to clone + * + * @return RequestInterface + * @throws \InvalidArgumentException if the method is not POST + */ + public static function convertPostToGet(RequestInterface $request, $additionalQueryParams = "") + { + if ($request->getMethod() !== 'POST') { + throw new \InvalidArgumentException('Expected a POST request but ' + . 'received a ' . $request->getMethod() . ' request.'); + } + + $sr = $request->withMethod('GET') + ->withBody(Psr7\Utils::streamFor('')) + ->withoutHeader('Content-Type') + ->withoutHeader('Content-Length'); + + // Move POST fields to the query if they are present + if ($request->getHeaderLine('Content-Type') === 'application/x-www-form-urlencoded') { + $body = (string) $request->getBody() . $additionalQueryParams; + $sr = $sr->withUri($sr->getUri()->withQuery($body)); + } + + return $sr; + } + + protected function getPayload(RequestInterface $request) + { + if ($this->unsigned && $request->getUri()->getScheme() == 'https') { + return self::UNSIGNED_PAYLOAD; + } + // Calculate the request signature payload + if ($request->hasHeader(self::AMZ_CONTENT_SHA256_HEADER)) { + // Handle streaming operations (e.g. Glacier.UploadArchive) + return $request->getHeaderLine(self::AMZ_CONTENT_SHA256_HEADER); + } + + if (!$request->getBody()->isSeekable()) { + throw new CouldNotCreateChecksumException('sha256'); + } + + try { + return Psr7\Utils::hash($request->getBody(), 'sha256'); + } catch (\Exception $e) { + throw new CouldNotCreateChecksumException('sha256', $e); + } + } + + protected function getPresignedPayload(RequestInterface $request) + { + return $this->getPayload($request); + } + + protected function createCanonicalizedPath($path) + { + $doubleEncoded = rawurlencode(ltrim($path, '/')); + + return '/' . str_replace('%2F', '/', $doubleEncoded); + } + + private function createStringToSign($longDate, $credentialScope, $creq) + { + $hash = hash('sha256', $creq); + + return "AWS4-HMAC-SHA256\n{$longDate}\n{$credentialScope}\n{$hash}"; + } + + private function createPresignedRequest( + RequestInterface $request, + CredentialsInterface $credentials + ) { + $parsedRequest = $this->parseRequest($request); + + // Make sure to handle temporary credentials + if ($token = $credentials->getSecurityToken()) { + $parsedRequest['headers']['X-Amz-Security-Token'] = [$token]; + } + + return $this->moveHeadersToQuery($parsedRequest); + } + + /** + * @param array $parsedRequest + * @param string $payload Hash of the request payload + * @return array Returns an array of context information + */ + private function createContext(array $parsedRequest, $payload) + { + $blacklist = $this->getHeaderBlacklist(); + + // Normalize the path as required by SigV4 + $canon = $parsedRequest['method'] . "\n" + . $this->createCanonicalizedPath($parsedRequest['path']) . "\n" + . $this->getCanonicalizedQuery($parsedRequest['query']) . "\n"; + + // Case-insensitively aggregate all of the headers. + $aggregate = []; + foreach ($parsedRequest['headers'] as $key => $values) { + $key = strtolower($key); + if (!isset($blacklist[$key])) { + foreach ($values as $v) { + $aggregate[$key][] = $v; + } + } + } + + ksort($aggregate); + $canonHeaders = []; + foreach ($aggregate as $k => $v) { + if (count($v) > 0) { + sort($v); + } + $canonHeaders[] = $k . ':' . preg_replace('/\s+/', ' ', implode(',', $v)); + } + + $signedHeadersString = implode(';', array_keys($aggregate)); + $canon .= implode("\n", $canonHeaders) . "\n\n" + . $signedHeadersString . "\n" + . $payload; + + return ['creq' => $canon, 'headers' => $signedHeadersString]; + } + + private function getCanonicalizedQuery(array $query) + { + unset($query['X-Amz-Signature']); + + if (!$query) { + return ''; + } + + $qs = ''; + ksort($query); + foreach ($query as $k => $v) { + if (!is_array($v)) { + $qs .= rawurlencode($k) . '=' . rawurlencode($v !== null ? $v : '') . '&'; + } else { + sort($v); + foreach ($v as $value) { + $qs .= rawurlencode($k) . '=' . rawurlencode($value !== null ? $value : '') . '&'; + } + } + } + + return substr($qs, 0, -1); + } + + private function convertToTimestamp($dateValue, $relativeTimeBase = null) + { + if ($dateValue instanceof \DateTimeInterface) { + $timestamp = $dateValue->getTimestamp(); + } elseif (!is_numeric($dateValue)) { + $timestamp = strtotime($dateValue, + $relativeTimeBase === null ? time() : $relativeTimeBase + ); + } else { + $timestamp = $dateValue; + } + + return $timestamp; + } + + private function convertExpires($expiresTimestamp, $startTimestamp) + { + $duration = $expiresTimestamp - $startTimestamp; + + // Ensure that the duration of the signature is not longer than a week + if ($duration > 604800) { + throw new \InvalidArgumentException('The expiration date of a ' + . 'signature version 4 presigned URL must be less than one ' + . 'week'); + } + + return $duration; + } + + private function moveHeadersToQuery(array $parsedRequest) + { + //x-amz-user-agent shouldn't be put in a query param + unset($parsedRequest['headers']['X-Amz-User-Agent']); + + foreach ($parsedRequest['headers'] as $name => $header) { + $lname = strtolower($name); + if (substr($lname, 0, 5) == 'x-amz') { + $parsedRequest['query'][$name] = $header; + } + $blacklist = $this->getHeaderBlacklist(); + if (isset($blacklist[$lname]) + || $lname === strtolower(self::AMZ_CONTENT_SHA256_HEADER) + ) { + unset($parsedRequest['headers'][$name]); + } + } + + return $parsedRequest; + } + + private function parseRequest(RequestInterface $request) + { + // Clean up any previously set headers. + /** @var RequestInterface $request */ + $request = $request + ->withoutHeader('X-Amz-Date') + ->withoutHeader('Date') + ->withoutHeader('Authorization'); + $uri = $request->getUri(); + + return [ + 'method' => $request->getMethod(), + 'path' => $uri->getPath(), + 'query' => Psr7\Query::parse($uri->getQuery()), + 'uri' => $uri, + 'headers' => $request->getHeaders(), + 'body' => $request->getBody(), + 'version' => $request->getProtocolVersion() + ]; + } + + private function buildRequest(array $req) + { + if ($req['query']) { + $req['uri'] = $req['uri']->withQuery(Psr7\Query::build($req['query'])); + } + + return new Psr7\Request( + $req['method'], + $req['uri'], + $req['headers'], + $req['body'], + $req['version'] + ); + } + + /** + * @param CredentialsInterface $credentials + * @param RequestInterface $request + * @param $signingService + * @return RequestInterface + */ + protected function signWithV4a(CredentialsInterface $credentials, RequestInterface $request, $signingService) + { + if (!extension_loaded('awscrt')) { + throw new CommonRuntimeException( + "AWS Common Runtime for PHP is required to use Signature V4A" + . ". Please install it using the instructions found at" + . " https://github.com/aws/aws-sdk-php/blob/master/CRT_INSTRUCTIONS.md" + ); + } + $credentials_provider = new StaticCredentialsProvider([ + 'access_key_id' => $credentials->getAccessKeyId(), + 'secret_access_key' => $credentials->getSecretKey(), + 'session_token' => $credentials->getSecurityToken(), + ]); + $sha = $this->getPayload($request); + $signingConfig = new SigningConfigAWS([ + 'algorithm' => SigningAlgorithm::SIGv4_ASYMMETRIC, + 'signature_type' => SignatureType::HTTP_REQUEST_HEADERS, + 'credentials_provider' => $credentials_provider, + 'signed_body_value' => $sha, + 'region' => "*", + 'service' => $signingService, + 'date' => time(), + ]); + $sha = $this->getPayload($request); + $invocationId = $request->getHeader("aws-sdk-invocation-id"); + $retry = $request->getHeader("aws-sdk-retry"); + $request = $request->withoutHeader("aws-sdk-invocation-id"); + $request = $request->withoutHeader("aws-sdk-retry"); + $http_request = new Request( + $request->getMethod(), + (string) $request->getUri(), + [], + array_map(function ($header) { + return $header[0]; + }, $request->getHeaders()) + ); + + Signing::signRequestAws( + Signable::fromHttpRequest($http_request), + $signingConfig, function ($signing_result, $error_code) use (&$http_request) { + $signing_result->applyToHttpRequest($http_request); + }); + $sigV4AHeaders = $http_request->headers(); + foreach ($sigV4AHeaders->toArray() as $h => $v) { + $request = $request->withHeader($h, $v); + } + $request = $request->withHeader("aws-sdk-invocation-id", $invocationId); + $request = $request->withHeader("x-amz-content-sha256", $sha); + $request = $request->withHeader("aws-sdk-retry", $retry); + $request = $request->withHeader("x-amz-region-set", "*"); + + return $request; + } +} |