| @@ -4,8 +4,9 @@ | ||
| 4 | 4 | |
| 5 | 5 | use Dudlewebs\WPMCS\s3\Aws\Credentials\CredentialsInterface; |
| 6 | 6 | use Dudlewebs\WPMCS\s3\AWS\CRT\Auth\Signable; |
| 7 | 7 | use Dudlewebs\WPMCS\s3\AWS\CRT\Auth\SignatureType; |
| 8 | +use Dudlewebs\WPMCS\s3\AWS\CRT\Auth\SignedBodyHeaderType; | |
| 8 | 9 | use Dudlewebs\WPMCS\s3\AWS\CRT\Auth\Signing; |
| 9 | 10 | use Dudlewebs\WPMCS\s3\AWS\CRT\Auth\SigningAlgorithm; |
| 10 | 11 | use Dudlewebs\WPMCS\s3\AWS\CRT\Auth\SigningConfigAWS; |
| 11 | 12 | use Dudlewebs\WPMCS\s3\AWS\CRT\Auth\StaticCredentialsProvider; |
| @@ -110,8 +111,11 @@ | ||
| 110 | 111 | public function presign(RequestInterface $request, CredentialsInterface $credentials, $expires, array $options = []) |
| 111 | 112 | { |
| 112 | 113 | $startTimestamp = isset($options['start_time']) ? $this->convertToTimestamp($options['start_time'], null) : \time(); |
| 113 | 114 | $expiresTimestamp = $this->convertToTimestamp($expires, $startTimestamp); |
| 115 | + if ($this->useV4a) { | |
| 116 | + return $this->presignWithV4a($request, $credentials, $this->convertExpires($expiresTimestamp, $startTimestamp)); | |
| 117 | + } | |
| 114 | 118 | $parsed = $this->createPresignedRequest($request, $credentials); |
| 115 | 119 | $payload = $this->getPresignedPayload($request); |
| 116 | 120 | $httpDate = \gmdate(self::ISO8601_BASIC, $startTimestamp); |
| 117 | 121 | $shortDate = \substr($httpDate, 0, 8); |
| @@ -299,40 +303,81 @@ | ||
| 299 | 303 | $req['uri'] = $req['uri']->withQuery(Psr7\Query::build($req['query'])); |
| 300 | 304 | } |
| 301 | 305 | return new Psr7\Request($req['method'], $req['uri'], $req['headers'], $req['body'], $req['version']); |
| 302 | 306 | } |
| 307 | + protected function verifyCRTLoaded() | |
| 308 | + { | |
| 309 | + if (!\extension_loaded('awscrt')) { | |
| 310 | + 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"); | |
| 311 | + } | |
| 312 | + } | |
| 313 | + protected function createCRTStaticCredentialsProvider($credentials) | |
| 314 | + { | |
| 315 | + return new StaticCredentialsProvider(['access_key_id' => $credentials->getAccessKeyId(), 'secret_access_key' => $credentials->getSecretKey(), 'session_token' => $credentials->getSecurityToken()]); | |
| 316 | + } | |
| 317 | + private function removeIllegalV4aHeaders(&$request) | |
| 318 | + { | |
| 319 | + static $illegalV4aHeaders = [self::AMZ_CONTENT_SHA256_HEADER, 'aws-sdk-invocation-id', 'aws-sdk-retry', 'x-amz-region-set', 'transfer-encoding']; | |
| 320 | + $storedHeaders = []; | |
| 321 | + foreach ($illegalV4aHeaders as $header) { | |
| 322 | + if ($request->hasHeader($header)) { | |
| 323 | + $storedHeaders[$header] = $request->getHeader($header); | |
| 324 | + $request = $request->withoutHeader($header); | |
| 325 | + } | |
| 326 | + } | |
| 327 | + return $storedHeaders; | |
| 328 | + } | |
| 329 | + private function CRTRequestFromGuzzleRequest($request) | |
| 330 | + { | |
| 331 | + return new Request( | |
| 332 | + $request->getMethod(), | |
| 333 | + (string) $request->getUri(), | |
| 334 | + [], | |
| 335 | + //leave empty as the query is parsed from the uri object | |
| 336 | + \array_map(function ($header) { | |
| 337 | + return $header[0]; | |
| 338 | + }, $request->getHeaders()) | |
| 339 | + ); | |
| 340 | + } | |
| 303 | 341 | /** |
| 304 | 342 | * @param CredentialsInterface $credentials |
| 305 | 343 | * @param RequestInterface $request |
| 306 | 344 | * @param $signingService |
| 345 | + * @param SigningConfigAWS|null $signingConfig | |
| 307 | 346 | * @return RequestInterface |
| 308 | 347 | */ |
| 309 | - protected function signWithV4a(CredentialsInterface $credentials, RequestInterface $request, $signingService) | |
| 348 | + protected function signWithV4a(CredentialsInterface $credentials, RequestInterface $request, $signingService, ?SigningConfigAWS $signingConfig = null) | |
| 310 | 349 | { |
| 311 | - if (!\extension_loaded('awscrt')) { | |
| 312 | - 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"); | |
| 313 | - } | |
| 314 | - $credentials_provider = new StaticCredentialsProvider(['access_key_id' => $credentials->getAccessKeyId(), 'secret_access_key' => $credentials->getSecretKey(), 'session_token' => $credentials->getSecurityToken()]); | |
| 315 | - $sha = $this->getPayload($request); | |
| 316 | - $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()]); | |
| 317 | - $sha = $this->getPayload($request); | |
| 318 | - $invocationId = $request->getHeader("aws-sdk-invocation-id"); | |
| 319 | - $retry = $request->getHeader("aws-sdk-retry"); | |
| 320 | - $request = $request->withoutHeader("aws-sdk-invocation-id"); | |
| 321 | - $request = $request->withoutHeader("aws-sdk-retry"); | |
| 322 | - $http_request = new Request($request->getMethod(), (string) $request->getUri(), [], \array_map(function ($header) { | |
| 323 | - return $header[0]; | |
| 324 | - }, $request->getHeaders())); | |
| 350 | + $this->verifyCRTLoaded(); | |
| 351 | + $signingConfig = $signingConfig ?? new SigningConfigAWS(['algorithm' => SigningAlgorithm::SIGv4_ASYMMETRIC, 'signature_type' => SignatureType::HTTP_REQUEST_HEADERS, 'credentials_provider' => $this->createCRTStaticCredentialsProvider($credentials), 'signed_body_value' => $this->getPayload($request), 'should_normalize_uri_path' => \true, 'use_double_uri_encode' => \true, 'region' => $this->region, 'service' => $signingService, 'date' => \time()]); | |
| 352 | + $removedIllegalHeaders = $this->removeIllegalV4aHeaders($request); | |
| 353 | + $http_request = $this->CRTRequestFromGuzzleRequest($request); | |
| 325 | 354 | Signing::signRequestAws(Signable::fromHttpRequest($http_request), $signingConfig, function ($signing_result, $error_code) use(&$http_request) { |
| 326 | 355 | $signing_result->applyToHttpRequest($http_request); |
| 327 | 356 | }); |
| 357 | + foreach ($removedIllegalHeaders as $header => $value) { | |
| 358 | + $request = $request->withHeader($header, $value); | |
| 359 | + } | |
| 328 | 360 | $sigV4AHeaders = $http_request->headers(); |
| 329 | 361 | foreach ($sigV4AHeaders->toArray() as $h => $v) { |
| 330 | 362 | $request = $request->withHeader($h, $v); |
| 331 | 363 | } |
| 332 | - $request = $request->withHeader("aws-sdk-invocation-id", $invocationId); | |
| 333 | - $request = $request->withHeader("x-amz-content-sha256", $sha); | |
| 334 | - $request = $request->withHeader("aws-sdk-retry", $retry); | |
| 335 | - $request = $request->withHeader("x-amz-region-set", "*"); | |
| 336 | 364 | return $request; |
| 365 | + } | |
| 366 | + protected function presignWithV4a(RequestInterface $request, CredentialsInterface $credentials, $expires) | |
| 367 | + { | |
| 368 | + $this->verifyCRTLoaded(); | |
| 369 | + $credentials_provider = $this->createCRTStaticCredentialsProvider($credentials); | |
| 370 | + $signingConfig = new SigningConfigAWS(['algorithm' => SigningAlgorithm::SIGv4_ASYMMETRIC, 'signature_type' => SignatureType::HTTP_REQUEST_QUERY_PARAMS, 'credentials_provider' => $credentials_provider, 'signed_body_value' => $this->getPresignedPayload($request), 'region' => "*", 'service' => $this->service, 'date' => \time(), 'expiration_in_seconds' => $expires]); | |
| 371 | + $this->removeIllegalV4aHeaders($request); | |
| 372 | + foreach ($this->getHeaderBlacklist() as $headerName => $headerValue) { | |
| 373 | + if ($request->hasHeader($headerName)) { | |
| 374 | + $request = $request->withoutHeader($headerName); | |
| 375 | + } | |
| 376 | + } | |
| 377 | + $http_request = $this->CRTRequestFromGuzzleRequest($request); | |
| 378 | + Signing::signRequestAws(Signable::fromHttpRequest($http_request), $signingConfig, function ($signing_result, $error_code) use(&$http_request) { | |
| 379 | + $signing_result->applyToHttpRequest($http_request); | |
| 380 | + }); | |
| 381 | + return $request->withUri(new Psr7\Uri($http_request->pathAndQuery())); | |
| 337 | 382 | } |
| 338 | 383 | } |