AWSClientProvider V4
a phpmae:Class in Amazon Web Services Integration
Provides a generic API client for Amazon Webservices which uses the signature version 4.
Public PHP Methods
-
signRequest(RequestInterface $request)
No documentation available.
-
getClient()
Get a Guzzle HTTP Client configured with AWS signature V4 authentication.
Source Code
<?php use Psr\Http\Message\RequestInterface; use GuzzleHttp\Handler\CurlHandler; use GuzzleHttp\HandlerStack, GuzzleHttp\Client, GuzzleHttp\Middleware; use CloudObjects\PhpMAE\ConfigLoader; /** * Implementation for coid://aws.3rd-party.co/AWSClientProvider/V4 */ class AWSClientProvider { private $awsAccessKeyId; private $awsSecretAccessKey; private $client; public function __construct(ConfigLoader $config) { $priorities = [ 'callerClass', 'callerClass.namespace' ]; $this->awsAccessKeyId = $config->get('coid://aws.3rd-party.co/accessKeyId', $priorities); $this->awsSecretAccessKey = $config->get('coid://aws.3rd-party.co/secretAccessKey', $priorities); if (!isset($this->awsAccessKeyId) || !isset($this->awsSecretAccessKey)) throw new \Exception("AWS credentials required."); } private function getService($segments) { if (((count($segments)==4 && $segments[2]=='amazonaws' && $segments[3]=='com') || (count($segments)==3 && $segments[1]=='amazonaws' && $segments[2]=='com')) && in_array($segments[0], [ 'appstream', 'cloudsearch', 'cloudtrail', 'monitoring', 'logs', 'cognito-identity', 'cognito-sync', 'dynamodb', 'ec2', 'elasticmapreduce', 'elastictranscoder', 'elasticache', 'glacier', 'kinesis', 'mechanicalturk', 'mobileanalytics', 'redshift', 'rds', 'route53', 'route53domains', 'email', 'sdb', 'sns', 'sqs', 'swf', 'autoscaling', 'cloudformation', 'datapipeline', 'directconnect', 'elasticbeanstalk', 'iam', 'importexport', 'opsworks', 'sts', 'storagegateway', 'support', 'elasticloadbalancing' ])) { return $segments[0]; } else return 's3'; } private function getRegion($segments) { if (count($segments)==4 && $segments[2]=='amazonaws' && $segments[3]=='com' && in_array($segments[1], [ 'us-east-1', 'us-west-2', 'us-west-1', 'eu-west-1', 'eu-central-1', 'ap-southeast-1', 'ap-southeast-2', 'ap-northeast-1', 'sa-east-1' ])) { return $segments[1]; } else return 'us-east-1'; } public function signRequest(RequestInterface $request) { $date = new \DateTime('UTC'); $request = $request->withHeader('x-amz-date', $date->format('Ymd\THis\Z')); if (get_class($request)=='GuzzleHttp\Psr7\Request') { $contentHash = hash('SHA256', $request->getBody()); } else { // pre-calculated hash for an empty string $contentHash = 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855'; } // Parse query (if any) $queryMap = []; if (!empty($request->getUri()->getQuery())) { $query = explode('&', $request->getUri()->getQuery()); foreach ($query as $q) { $kv = explode('=', $q); $queryMap[$kv[0]] = urlencode($kv[1]); } uksort($queryMap, 'strcmp'); } // Prepare canonical request $canonicalRequest = array( $request->getMethod(), str_replace('%2F','/', rawurlencode($request->getUri()->getPath())), http_build_query($queryMap) ); foreach ($request->getHeaders() as $name => $values) { $headers[strtolower($name)] = trim((string)$values[0]); } uksort($headers, 'strcmp'); foreach ($headers as $key => $value) { $canonicalRequest[] = $key.':'.$value; } $canonicalRequest[] = ''; $canonicalRequest[] = implode(';', array_keys($headers)); $canonicalRequest[] = $contentHash; // Prepare string for signing $segments = explode('.', $request->getUri()->getHost()); $service = $this->getService($segments); $region = $this->getRegion($segments); $scope = $date->format('Ymd').'/'.$region.'/'.$service.'/aws4_request'; $string = implode("\n", array( 'AWS4-HMAC-SHA256', $date->format('Ymd\THis\Z'), $scope, hash('SHA256', implode("\n", $canonicalRequest)) )); // Create signature $kSecret = 'AWS4'.$this->awsSecretAccessKey; $kDate = hash_hmac('SHA256', $date->format('Ymd'), $kSecret, true); $kRegion = hash_hmac('SHA256', $region, $kDate, true); $kService = hash_hmac('SHA256', $service, $kRegion, true); $kSigning = hash_hmac('SHA256', 'aws4_request', $kService, true); $signature = hash_hmac('SHA256', $string, $kSigning); // Prepare authorization header $authorization = array( 'Credential='.$this->awsAccessKeyId.'/'.$scope, 'SignedHeaders='.implode(';', array_keys($headers)), 'Signature='.$signature, ); //die('AWS4-HMAC-SHA256'.' '.implode(',', $authorization)); $request = $request->withHeader('x-amz-content-sha256', $contentHash) ->withHeader('Authorization', 'AWS4-HMAC-SHA256'.' '.implode(',', $authorization)); return $request; } /** * Get a Guzzle HTTP Client configured with AWS signature V4 authentication. */ public function getClient() { if (!isset($this->client)) { $stack = new HandlerStack(); $stack->setHandler(new CurlHandler()); $stack->push(Middleware::mapRequest([$this, 'signRequest'])); $stack->push(Middleware::httpErrors()); $this->client = new Client([ 'handler' => $stack ]); } return $this->client; } }
Meta
- URI / COID
- coid://aws.3rd-party.co/AWSClientProvider/V4 content_copy
- Revision
- 3-47ecd846795844fe3d87a3acfa38a420 content_copy
- Short ID
- aws:AWSClientProvider/V4 content_copy
- Reference URL
- https://coid.link/aws.3rd-party.co/AWSClientProvider/V4 content_copy
- Last updated
- 2021-04-22 11:26 (UTC)
- Created at
- 2021-04-22 11:26 (UTC)