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)