提交服务端基础框架

This commit is contained in:
wanghao
2025-03-12 12:21:57 +08:00
parent 023758147a
commit 1ee65ad34e
1471 changed files with 284825 additions and 0 deletions

View File

@@ -0,0 +1,72 @@
<?php
namespace AlibabaCloud\Credentials;
use AlibabaCloud\Credentials\Signature\ShaHmac1Signature;
/**
* Use the AccessKey to complete the authentication.
*/
class AccessKeyCredential implements CredentialsInterface
{
/**
* @var string
*/
private $accessKeyId;
/**
* @var string
*/
private $accessKeySecret;
/**
* AccessKeyCredential constructor.
*
* @param string $access_key_id Access key ID
* @param string $access_key_secret Access Key Secret
*/
public function __construct($access_key_id, $access_key_secret)
{
Filter::accessKey($access_key_id, $access_key_secret);
$this->accessKeyId = $access_key_id;
$this->accessKeySecret = $access_key_secret;
}
/**
* @return string
*/
public function getAccessKeyId()
{
return $this->accessKeyId;
}
/**
* @return string
*/
public function getAccessKeySecret()
{
return $this->accessKeySecret;
}
/**
* @return string
*/
public function __toString()
{
return "$this->accessKeyId#$this->accessKeySecret";
}
/**
* @return ShaHmac1Signature
*/
public function getSignature()
{
return new ShaHmac1Signature();
}
public function getSecurityToken()
{
return '';
}
}

View File

@@ -0,0 +1,53 @@
<?php
namespace AlibabaCloud\Credentials;
use AlibabaCloud\Credentials\Signature\BearerTokenSignature;
/**
* Class BearerTokenCredential
*/
class BearerTokenCredential implements CredentialsInterface
{
/**
* @var string
*/
private $bearerToken;
/**
* BearerTokenCredential constructor.
*
* @param $bearerToken
*/
public function __construct($bearerToken)
{
Filter::bearerToken($bearerToken);
$this->bearerToken = $bearerToken;
}
/**
* @return string
*/
public function getBearerToken()
{
return $this->bearerToken;
}
/**
* @return string
*/
public function __toString()
{
return "bearerToken#$this->bearerToken";
}
/**
* @return BearerTokenSignature
*/
public function getSignature()
{
return new BearerTokenSignature();
}
}

View File

@@ -0,0 +1,182 @@
<?php
namespace AlibabaCloud\Credentials;
use AlibabaCloud\Credentials\Credential\Config;
use InvalidArgumentException;
use ReflectionClass;
use ReflectionException;
use ReflectionParameter;
/**
* Class Credential
*
* @package AlibabaCloud\Credentials
*
* @mixin AccessKeyCredential
* @mixin BearerTokenCredential
* @mixin EcsRamRoleCredential
* @mixin RamRoleArnCredential
* @mixin RsaKeyPairCredential
*/
class Credential
{
/**
* @var array
*/
protected $config = [];
/**
* @var array
*/
protected $types = [
'access_key' => AccessKeyCredential::class,
'sts' => StsCredential::class,
'ecs_ram_role' => EcsRamRoleCredential::class,
'ram_role_arn' => RamRoleArnCredential::class,
'rsa_key_pair' => RsaKeyPairCredential::class,
];
/**
* @var AccessKeyCredential|BearerTokenCredential|EcsRamRoleCredential|RamRoleArnCredential|RsaKeyPairCredential
*/
protected $credential;
/**
* @var string
*/
protected $type;
/**
* Credential constructor.
*
* @param array|Config $config
*
* @throws ReflectionException
*/
public function __construct($config = [])
{
if ($config instanceof Config) {
$config = $this->parse($config);
}
if ($config !== []) {
$this->config = array_change_key_case($config);
$this->parseConfig();
} else {
$this->credential = Credentials::get()->getCredential();
}
}
/**
* @param Config $config
*
* @return array
*/
private function parse($config)
{
$config = get_object_vars($config);
$res = [];
foreach ($config as $key => $value) {
$res[$this->toUnderScore($key)] = $value;
}
return $res;
}
private function toUnderScore($str)
{
$dstr = preg_replace_callback('/([A-Z]+)/', function ($matchs) {
return '_' . strtolower($matchs[0]);
}, $str);
return trim(preg_replace('/_{2,}/', '_', $dstr), '_');
}
/**
* @throws ReflectionException
*/
private function parseConfig()
{
if (!isset($this->config['type'])) {
throw new InvalidArgumentException('Missing required type option');
}
$this->type = $this->config['type'];
if (!isset($this->types[$this->type])) {
throw new InvalidArgumentException(
'Invalid type option, support: ' .
implode(', ', array_keys($this->types))
);
}
$class = new ReflectionClass($this->types[$this->type]);
$parameters = [];
/**
* @var $parameter ReflectionParameter
*/
foreach ($class->getConstructor()->getParameters() as $parameter) {
$parameters[] = $this->getValue($parameter);
}
$this->credential = $class->newInstance(...$parameters);
}
/**
* @param ReflectionParameter $parameter
*
* @return string|array
* @throws ReflectionException
*/
protected function getValue(ReflectionParameter $parameter)
{
if ($parameter->name === 'config' || $parameter->name === 'credential') {
return $this->config;
}
foreach ($this->config as $key => $value) {
if (strtolower($parameter->name) === $key) {
return $value;
}
}
if ($parameter->isDefaultValueAvailable()) {
return $parameter->getDefaultValue();
}
throw new InvalidArgumentException("Missing required {$parameter->name} option in config for {$this->type}");
}
/**
* @return AccessKeyCredential|BearerTokenCredential|EcsRamRoleCredential|RamRoleArnCredential|RsaKeyPairCredential
*/
public function getCredential()
{
return $this->credential;
}
/**
* @return array
*/
public function getConfig()
{
return $this->config;
}
/**
* @return string
*/
public function getType()
{
return $this->type;
}
/**
* @param string $name
* @param array $arguments
*
* @return mixed
*/
public function __call($name, $arguments)
{
return $this->credential->$name($arguments);
}
}

View File

@@ -0,0 +1,50 @@
<?php
namespace AlibabaCloud\Credentials\Credential;
class Config
{
/**
* @var string
*/
public $type = 'default';
public $accessKeyId = "";
public $accessKeySecret = "";
public $securityToken = "";
public $bearerToken = "";
public $roleName = "";
public $roleArn = "";
public $roleSessionName = "";
public $host = "";
public $publicKeyId = "";
public $privateKeyFile = "";
public $readTimeout = 0;
public $connectTimeout = 0;
public $certFile = "";
public $certPassword = "";
public $proxy = "";
public $expiration = 0;
public function __construct($config)
{
foreach ($config as $k => $v) {
$this->{$k} = $v;
}
}
}

View File

@@ -0,0 +1,102 @@
<?php
namespace AlibabaCloud\Credentials;
use AlibabaCloud\Credentials\Providers\ChainProvider;
use ReflectionException;
use RuntimeException;
/**
* Class Credentials
*
* @package AlibabaCloud\Credentials
*/
class Credentials
{
use MockTrait;
/**
* @var array|CredentialsInterface[] containers of credentials
*/
protected static $credentials = [];
/**
* Get the credential instance by name.
*
* @param string $name
*
* @return Credential
* @throws ReflectionException
*/
public static function get($name = null)
{
if ($name !== null) {
Filter::credentialName($name);
} else {
$name = ChainProvider::getDefaultName();
}
self::load();
if (self::has($name)) {
return new Credential(self::$credentials[\strtolower($name)]);
}
throw new RuntimeException("Credential '$name' not found");
}
private static function load()
{
if (self::$credentials) {
return;
}
if (ChainProvider::hasCustomChain()) {
ChainProvider::customProvider(ChainProvider::getDefaultName());
} else {
ChainProvider::defaultProvider(ChainProvider::getDefaultName());
}
}
/**
* Determine whether there is a credential.
*
* @param string $name
*
* @return bool
*/
public static function has($name)
{
Filter::credentialName($name);
return isset(self::$credentials[\strtolower($name)]);
}
public static function flush()
{
self::$credentials = [];
}
/**
* Get all credentials.
*
* @return array
*/
public static function all()
{
self::load();
return self::$credentials;
}
/**
* @param string $name
* @param array $credential
*/
public static function set($name, array $credential)
{
Filter::credentialName($name);
self::$credentials[\strtolower($name)] = \array_change_key_case($credential);
}
}

View File

@@ -0,0 +1,23 @@
<?php
namespace AlibabaCloud\Credentials;
use AlibabaCloud\Credentials\Signature\SignatureInterface;
/**
* Interface CredentialsInterface
*
* @codeCoverageIgnore
*/
interface CredentialsInterface
{
/**
* @return string
*/
public function __toString();
/**
* @return SignatureInterface
*/
public function getSignature();
}

View File

@@ -0,0 +1,151 @@
<?php
namespace AlibabaCloud\Credentials;
use AlibabaCloud\Credentials\Providers\EcsRamRoleProvider;
use AlibabaCloud\Credentials\Request\Request;
use AlibabaCloud\Credentials\Signature\ShaHmac1Signature;
use Exception;
use GuzzleHttp\Exception\GuzzleException;
use InvalidArgumentException;
use RuntimeException;
/**
* Use the RAM role of an ECS instance to complete the authentication.
*/
class EcsRamRoleCredential implements CredentialsInterface
{
/**
* @var string
*/
private $roleName;
/**
* EcsRamRoleCredential constructor.
*
* @param $role_name
*/
public function __construct($role_name = null)
{
Filter::roleName($role_name);
$this->roleName = $role_name;
}
/**
* @return string
* @throws GuzzleException
* @throws Exception
*/
public function getRoleName()
{
if ($this->roleName !== null) {
return $this->roleName;
}
$this->roleName = $this->getRoleNameFromMeta();
return $this->roleName;
}
/**
* @return string
* @throws Exception
*/
public function getRoleNameFromMeta()
{
$options = [
'http_errors' => false,
'timeout' => 1,
'connect_timeout' => 1,
];
$result = Request::createClient()->request(
'GET',
'http://100.100.100.200/latest/meta-data/ram/security-credentials/',
$options
);
if ($result->getStatusCode() === 404) {
throw new InvalidArgumentException('The role name was not found in the instance');
}
if ($result->getStatusCode() !== 200) {
throw new RuntimeException('Error retrieving credentials from result: ' . $result->getBody());
}
$role_name = (string)$result;
if (!$role_name) {
throw new RuntimeException('Error retrieving credentials from result is empty');
}
return $role_name;
}
/**
* @return string
*/
public function __toString()
{
return "roleName#$this->roleName";
}
/**
* @return ShaHmac1Signature
*/
public function getSignature()
{
return new ShaHmac1Signature();
}
/**
* @return string
* @throws Exception
* @throws GuzzleException
*/
public function getAccessKeyId()
{
return $this->getSessionCredential()->getAccessKeyId();
}
/**
* @return StsCredential
* @throws Exception
* @throws GuzzleException
*/
protected function getSessionCredential()
{
return (new EcsRamRoleProvider($this))->get();
}
/**
* @return string
* @throws Exception
* @throws GuzzleException
*/
public function getAccessKeySecret()
{
return $this->getSessionCredential()->getAccessKeySecret();
}
/**
* @return string
* @throws Exception
* @throws GuzzleException
*/
public function getSecurityToken()
{
return $this->getSessionCredential()->getSecurityToken();
}
/**
* @return int
* @throws Exception
* @throws GuzzleException
*/
public function getExpiration()
{
return $this->getSessionCredential()->getExpiration();
}
}

View File

@@ -0,0 +1,134 @@
<?php
namespace AlibabaCloud\Credentials;
use InvalidArgumentException;
class Filter
{
/**
* @param $name
*
* @codeCoverageIgnore
* @return string
*/
public static function credentialName($name)
{
if (!is_string($name)) {
throw new InvalidArgumentException('Name must be a string');
}
if ($name === '') {
throw new InvalidArgumentException('Name cannot be empty');
}
return $name;
}
/**
* @param $bearerToken
*
* @return mixed
* @throws InvalidArgumentException
*/
public static function bearerToken($bearerToken)
{
if (!is_string($bearerToken)) {
throw new InvalidArgumentException('Bearer Token must be a string');
}
if ($bearerToken === '') {
throw new InvalidArgumentException('Bearer Token cannot be empty');
}
return $bearerToken;
}
/**
* @param $publicKeyId
*
* @return mixed
*/
public static function publicKeyId($publicKeyId)
{
if (!is_string($publicKeyId)) {
throw new InvalidArgumentException('public_key_id must be a string');
}
if ($publicKeyId === '') {
throw new InvalidArgumentException('public_key_id cannot be empty');
}
return $publicKeyId;
}
/**
* @param $privateKeyFile
*
* @return mixed
*/
public static function privateKeyFile($privateKeyFile)
{
if (!is_string($privateKeyFile)) {
throw new InvalidArgumentException('private_key_file must be a string');
}
if ($privateKeyFile === '') {
throw new InvalidArgumentException('private_key_file cannot be empty');
}
return $privateKeyFile;
}
/**
* @param string|null $role_name
*/
public static function roleName($role_name)
{
if ($role_name === null) {
return;
}
if (!is_string($role_name)) {
throw new InvalidArgumentException('role_name must be a string');
}
if ($role_name === '') {
throw new InvalidArgumentException('role_name cannot be empty');
}
}
/**
* @param string $accessKeyId
* @param string $accessKeySecret
*/
public static function accessKey($accessKeyId, $accessKeySecret)
{
if (!is_string($accessKeyId)) {
throw new InvalidArgumentException('access_key_id must be a string');
}
if ($accessKeyId === '') {
throw new InvalidArgumentException('access_key_id cannot be empty');
}
if (!is_string($accessKeySecret)) {
throw new InvalidArgumentException('access_key_secret must be a string');
}
if ($accessKeySecret === '') {
throw new InvalidArgumentException('access_key_secret cannot be empty');
}
}
/**
* @param int $expiration
*/
public static function expiration($expiration)
{
if (!is_int($expiration)) {
throw new InvalidArgumentException('expiration must be a int');
}
}
}

View File

@@ -0,0 +1,202 @@
<?php
namespace AlibabaCloud\Credentials;
use Closure;
/**
* Class Helper
*
* @package AlibabaCloud\Credentials
*/
class Helper
{
/**
* @param array $arrays
*
* @return array
*/
public static function merge(array $arrays)
{
$result = [];
foreach ($arrays as $array) {
foreach ($array as $key => $value) {
if (is_int($key)) {
$result[] = $value;
continue;
}
if (isset($result[$key]) && is_array($result[$key])) {
$result[$key] = self::merge(
[$result[$key], $value]
);
continue;
}
$result[$key] = $value;
}
}
return $result;
}
/**
* @param $filename
*
* @return bool
*/
public static function inOpenBasedir($filename)
{
$open_basedir = ini_get('open_basedir');
if (!$open_basedir) {
return true;
}
$dirs = explode(PATH_SEPARATOR, $open_basedir);
return empty($dirs) || self::inDir($filename, $dirs);
}
/**
* @param string $filename
* @param array $dirs
*
* @return bool
*/
public static function inDir($filename, array $dirs)
{
foreach ($dirs as $dir) {
if ($dir[strlen($dir) - 1] !== DIRECTORY_SEPARATOR) {
$dir .= DIRECTORY_SEPARATOR;
}
if (0 === strpos($filename, $dir)) {
return true;
}
}
return false;
}
/**
* @return bool
*/
public static function isWindows()
{
return PATH_SEPARATOR === ';';
}
/**
* @param $key
*
* @return bool|mixed
*/
public static function envNotEmpty($key)
{
$value = self::env($key, false);
if ($value) {
return $value;
}
return false;
}
/**
* Gets the value of an environment variable.
*
* @param string $key
* @param mixed $default
*
* @return mixed
*/
public static function env($key, $default = null)
{
$value = getenv($key);
if ($value === false) {
return self::value($default);
}
if (self::envSubstr($value)) {
return substr($value, 1, -1);
}
return self::envConversion($value);
}
/**
* Return the default value of the given value.
*
* @param mixed $value
*
* @return mixed
*/
public static function value($value)
{
return $value instanceof Closure ? $value() : $value;
}
/**
* @param $value
*
* @return bool
*/
public static function envSubstr($value)
{
return ($valueLength = strlen($value)) > 1
&& strpos($value, '"') === 0
&& $value[$valueLength - 1] === '"';
}
/**
* @param $value
*
* @return bool|string|null
*/
public static function envConversion($value)
{
$key = strtolower($value);
if ($key === 'null' || $key === '(null)') {
return null;
}
$list = [
'true' => true,
'(true)' => true,
'false' => false,
'(false)' => false,
'empty' => '',
'(empty)' => '',
];
return isset($list[$key]) ? $list[$key] : $value;
}
/**
* Gets the environment's HOME directory.
*
* @return null|string
*/
public static function getHomeDirectory()
{
if (getenv('HOME')) {
return getenv('HOME');
}
return (getenv('HOMEDRIVE') && getenv('HOMEPATH'))
? getenv('HOMEDRIVE') . getenv('HOMEPATH')
: null;
}
/**
* @param mixed ...$parameters
*
* @codeCoverageIgnore
*/
public static function dd(...$parameters)
{
dump(...$parameters);
exit;
}
}

View File

@@ -0,0 +1,98 @@
<?php
namespace AlibabaCloud\Credentials;
use Exception;
use GuzzleHttp\Exception\RequestException;
use GuzzleHttp\Handler\MockHandler;
use GuzzleHttp\Psr7\Response;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;
/**
* Trait MockTrait
*
* @package AlibabaCloud\Credentials
*/
trait MockTrait
{
/**
* @var array
*/
private static $mockQueue = [];
/**
* @var MockHandler
*/
private static $mock;
/**
* @param integer $status
* @param array $headers
* @param array|string|object $body
*/
public static function mockResponse($status = 200, array $headers = [], $body = null)
{
if (is_array($body) || is_object($body)) {
$body = json_encode($body);
}
self::$mockQueue[] = new Response($status, $headers, $body);
self::createHandlerStack();
}
private static function createHandlerStack()
{
self::$mock = new MockHandler(self::$mockQueue);
}
/**
* @param string $message
* @param RequestInterface $request
* @param ResponseInterface|null $response
* @param Exception|null $previous
* @param array $handlerContext
*/
public static function mockRequestException(
$message,
RequestInterface $request,
ResponseInterface $response = null,
Exception $previous = null,
array $handlerContext = []
) {
self::$mockQueue[] = new RequestException(
$message,
$request,
$response,
$previous,
$handlerContext
);
self::createHandlerStack();
}
/**
* @return void
*/
public static function cancelMock()
{
self::$mockQueue = [];
self::$mock = null;
}
/**
* @return bool
*/
public static function hasMock()
{
return (bool)self::$mockQueue;
}
/**
* @return MockHandler
*/
public static function getMock()
{
return self::$mock;
}
}

View File

@@ -0,0 +1,187 @@
<?php
namespace AlibabaCloud\Credentials\Providers;
use AlibabaCloud\Credentials\Credentials;
use AlibabaCloud\Credentials\Helper;
use Closure;
use InvalidArgumentException;
use RuntimeException;
/**
* Class ChainProvider
*
* @package AlibabaCloud\Credentials\Providers
*/
class ChainProvider
{
/**
* @var array
*/
private static $customChains;
/**
* @param callable ...$providers
*/
public static function set(...$providers)
{
if (empty($providers)) {
throw new InvalidArgumentException('No providers in chain');
}
foreach ($providers as $provider) {
if (!$provider instanceof Closure) {
throw new InvalidArgumentException('Providers must all be Closures');
}
}
self::$customChains = $providers;
}
/**
* @return bool
*/
public static function hasCustomChain()
{
return (bool)self::$customChains;
}
public static function flush()
{
self::$customChains = [];
}
/**
* @param string $name
*/
public static function customProvider($name)
{
foreach (self::$customChains as $provider) {
$provider();
if (Credentials::has($name)) {
break;
}
}
}
/**
* @param string $name
*/
public static function defaultProvider($name)
{
$providers = [
self::env(),
self::ini(),
self::instance(),
];
foreach ($providers as $provider) {
$provider();
if (Credentials::has($name)) {
break;
}
}
}
/**
* @return Closure
*/
public static function env()
{
return static function () {
$accessKeyId = Helper::envNotEmpty('ALIBABA_CLOUD_ACCESS_KEY_ID');
$accessKeySecret = Helper::envNotEmpty('ALIBABA_CLOUD_ACCESS_KEY_SECRET');
if ($accessKeyId && $accessKeySecret) {
Credentials::set(
self::getDefaultName(),
[
'type' => 'access_key',
'access_key_id' => $accessKeyId,
'access_key_secret' => $accessKeySecret,
]
);
}
};
}
/**
* @return string
*/
public static function getDefaultName()
{
$name = Helper::envNotEmpty('ALIBABA_CLOUD_PROFILE');
if ($name) {
return $name;
}
return 'default';
}
/**
* @return Closure
*/
public static function ini()
{
return static function () {
$filename = Helper::envNotEmpty('ALIBABA_CLOUD_CREDENTIALS_FILE');
if (!$filename) {
$filename = self::getDefaultFile();
}
if (!Helper::inOpenBasedir($filename)) {
return;
}
if ($filename !== self::getDefaultFile() && (!\is_readable($filename) || !\is_file($filename))) {
throw new RuntimeException(
'Credentials file is not readable: ' . $filename
);
}
$file_array = \parse_ini_file($filename, true);
if (\is_array($file_array) && !empty($file_array)) {
foreach (\array_change_key_case($file_array) as $name => $configures) {
Credentials::set($name, $configures);
}
}
};
}
/**
* Get the default credential file.
*
* @return string
*/
public static function getDefaultFile()
{
return Helper::getHomeDirectory() .
DIRECTORY_SEPARATOR .
'.alibabacloud' .
DIRECTORY_SEPARATOR .
'credentials';
}
/**
* @return Closure
*/
public static function instance()
{
return static function () {
$instance = Helper::envNotEmpty('ALIBABA_CLOUD_ECS_METADATA');
if ($instance) {
Credentials::set(
self::getDefaultName(),
[
'type' => 'ecs_ram_role',
'role_name' => $instance,
]
);
}
};
}
}

View File

@@ -0,0 +1,94 @@
<?php
namespace AlibabaCloud\Credentials\Providers;
use AlibabaCloud\Credentials\Request\Request;
use AlibabaCloud\Credentials\StsCredential;
use Exception;
use GuzzleHttp\Exception\GuzzleException;
use AlibabaCloud\Tea\Response;
use InvalidArgumentException;
use Psr\Http\Message\ResponseInterface;
use RuntimeException;
/**
* Class EcsRamRoleProvider
*
* @package AlibabaCloud\Credentials\Providers
*/
class EcsRamRoleProvider extends Provider
{
/**
* Expiration time slot for temporary security credentials.
*
* @var int
*/
protected $expirationSlot = 10;
/**
* @var string
*/
private $uri = 'http://100.100.100.200/latest/meta-data/ram/security-credentials/';
/**
* Get credential.
*
* @return StsCredential
* @throws Exception
* @throws GuzzleException
*/
public function get()
{
$result = $this->getCredentialsInCache();
if ($result === null) {
$result = $this->request();
if (!isset($result['AccessKeyId'], $result['AccessKeySecret'], $result['SecurityToken'])) {
throw new RuntimeException($this->error);
}
$this->cache($result->toArray());
}
return new StsCredential(
$result['AccessKeyId'],
$result['AccessKeySecret'],
strtotime($result['Expiration']),
$result['SecurityToken']
);
}
/**
* Get credentials by request.
*
* @return ResponseInterface
* @throws Exception
* @throws GuzzleException
*/
public function request()
{
$credential = $this->credential;
$url = $this->uri . $credential->getRoleName();
$options = [
'http_errors' => false,
'timeout' => 1,
'connect_timeout' => 1,
];
$result = Request::createClient()->request('GET', $url, $options);
if ($result->getStatusCode() === 404) {
$message = 'The role was not found in the instance';
throw new InvalidArgumentException($message);
}
if ($result->getStatusCode() !== 200) {
throw new RuntimeException('Error retrieving credentials from result: ' . $result->toJson());
}
return $result;
}
}

View File

@@ -0,0 +1,82 @@
<?php
namespace AlibabaCloud\Credentials\Providers;
use AlibabaCloud\Credentials\CredentialsInterface;
use AlibabaCloud\Credentials\EcsRamRoleCredential;
use AlibabaCloud\Credentials\RamRoleArnCredential;
use AlibabaCloud\Credentials\RsaKeyPairCredential;
abstract class Provider
{
/**
* For TSC Duration Seconds
*/
const DURATION_SECONDS = 3600;
/**
* @var array
*/
protected static $credentialsCache = [];
/**
* Expiration time slot for temporary security credentials.
*
* @var int
*/
protected $expirationSlot = 180;
/**
* @var RamRoleArnCredential|RsaKeyPairCredential|EcsRamRoleCredential
*/
protected $credential;
/**
* @var string
*/
protected $error = 'Result contains no credentials';
/**
* @var array
*/
protected $config = [];
/**
* CredentialTrait constructor.
*
* @param CredentialsInterface $credential
* @param array $config
*/
public function __construct(CredentialsInterface $credential, $config = [])
{
$this->credential = $credential;
$this->config = $config;
}
/**
* Get the credentials from the cache in the validity period.
*
* @return array|null
*/
public function getCredentialsInCache()
{
if (isset(self::$credentialsCache[(string)$this->credential])) {
$result = self::$credentialsCache[(string)$this->credential];
if (\strtotime($result['Expiration']) - \time() >= $this->expirationSlot) {
return $result;
}
}
return null;
}
/**
* Cache credentials.
*
* @param array $credential
*/
protected function cache(array $credential)
{
self::$credentialsCache[(string)$this->credential] = $credential;
}
}

View File

@@ -0,0 +1,49 @@
<?php
namespace AlibabaCloud\Credentials\Providers;
use AlibabaCloud\Credentials\Request\AssumeRole;
use AlibabaCloud\Credentials\StsCredential;
use Exception;
use GuzzleHttp\Exception\GuzzleException;
use RuntimeException;
class RamRoleArnProvider extends Provider
{
/**
* Get credential.
*
* @return StsCredential
* @throws Exception
* @throws GuzzleException
*/
public function get()
{
$credential = $this->getCredentialsInCache();
if (null === $credential) {
$result = (new AssumeRole($this->credential))->request();
if ($result->getStatusCode() !== 200) {
throw new RuntimeException(isset($result['Message']) ? $result['Message'] : (string)$result->getBody());
}
if (!isset($result['Credentials']['AccessKeyId'],
$result['Credentials']['AccessKeySecret'],
$result['Credentials']['SecurityToken'])) {
throw new RuntimeException($this->error);
}
$credential = $result['Credentials'];
$this->cache($credential);
}
return new StsCredential(
$credential['AccessKeyId'],
$credential['AccessKeySecret'],
strtotime($credential['Expiration']),
$credential['SecurityToken']
);
}
}

View File

@@ -0,0 +1,53 @@
<?php
namespace AlibabaCloud\Credentials\Providers;
use AlibabaCloud\Credentials\Request\GenerateSessionAccessKey;
use AlibabaCloud\Credentials\StsCredential;
use Exception;
use GuzzleHttp\Exception\GuzzleException;
use RuntimeException;
/**
* Class RsaKeyPairProvider
*
* @package AlibabaCloud\Credentials\Providers
*/
class RsaKeyPairProvider extends Provider
{
/**
* Get credential.
*
*
* @return StsCredential
* @throws Exception
* @throws GuzzleException
*/
public function get()
{
$credential = $this->getCredentialsInCache();
if ($credential === null) {
$result = (new GenerateSessionAccessKey($this->credential))->request();
if ($result->getStatusCode() !== 200) {
throw new RuntimeException(isset($result['Message']) ? $result['Message'] : (string)$result->getBody());
}
if (!isset($result['SessionAccessKey']['SessionAccessKeyId'],
$result['SessionAccessKey']['SessionAccessKeySecret'])) {
throw new RuntimeException($this->error);
}
$credential = $result['SessionAccessKey'];
$this->cache($credential);
}
return new StsCredential(
$credential['SessionAccessKeyId'],
$credential['SessionAccessKeySecret'],
strtotime($credential['Expiration'])
);
}
}

View File

@@ -0,0 +1,218 @@
<?php
namespace AlibabaCloud\Credentials;
use AlibabaCloud\Credentials\Providers\RamRoleArnProvider;
use AlibabaCloud\Credentials\Signature\ShaHmac1Signature;
use Exception;
use GuzzleHttp\Exception\GuzzleException;
use InvalidArgumentException;
/**
* Use the AssumeRole of the RAM account to complete the authentication.
*/
class RamRoleArnCredential implements CredentialsInterface
{
/**
* @var string
*/
private $accessKeyId;
/**
* @var string
*/
private $accessKeySecret;
/**
* @var string
*/
private $roleArn;
/**
* @var string
*/
private $roleSessionName;
/**
* @var string
*/
private $policy;
/**
* @var array
*/
private $config;
/**
* RamRoleArnCredential constructor.
*
* @param array $credential
* @param array $config
*/
public function __construct(array $credential = [], array $config = [])
{
$this->filterParameters($credential);
$this->filterPolicy($credential);
Filter::accessKey($credential['access_key_id'], $credential['access_key_secret']);
$this->config = $config;
$this->accessKeyId = $credential['access_key_id'];
$this->accessKeySecret = $credential['access_key_secret'];
$this->roleArn = $credential['role_arn'];
$this->roleSessionName = $credential['role_session_name'];
}
/**
* @param array $credential
*/
private function filterParameters(array $credential)
{
if (!isset($credential['access_key_id'])) {
throw new InvalidArgumentException('Missing required access_key_id option in config for ram_role_arn');
}
if (!isset($credential['access_key_secret'])) {
throw new InvalidArgumentException('Missing required access_key_secret option in config for ram_role_arn');
}
if (!isset($credential['role_arn'])) {
throw new InvalidArgumentException('Missing required role_arn option in config for ram_role_arn');
}
if (!isset($credential['role_session_name'])) {
throw new InvalidArgumentException('Missing required role_session_name option in config for ram_role_arn');
}
}
/**
* @param array $credential
*/
private function filterPolicy(array $credential)
{
if (isset($credential['policy'])) {
if (is_string($credential['policy'])) {
$this->policy = $credential['policy'];
}
if (is_array($credential['policy'])) {
$this->policy = json_encode($credential['policy']);
}
}
}
/**
* @return array
*/
public function getConfig()
{
return $this->config;
}
/**
* @return string
*/
public function getRoleArn()
{
return $this->roleArn;
}
/**
* @return string
*/
public function getRoleSessionName()
{
return $this->roleSessionName;
}
/**
* @return string
*/
public function getPolicy()
{
return $this->policy;
}
/**
* @return string
*/
public function __toString()
{
return "$this->accessKeyId#$this->accessKeySecret#$this->roleArn#$this->roleSessionName";
}
/**
* @return ShaHmac1Signature
*/
public function getSignature()
{
return new ShaHmac1Signature();
}
/**
* @return string
*/
public function getOriginalAccessKeyId()
{
return $this->accessKeyId;
}
/**
* @return string
*/
public function getOriginalAccessKeySecret()
{
return $this->accessKeySecret;
}
/**
* @return string
* @throws Exception
* @throws GuzzleException
*/
public function getAccessKeyId()
{
return $this->getSessionCredential()->getAccessKeyId();
}
/**
* @return StsCredential
* @throws Exception
* @throws GuzzleException
*/
protected function getSessionCredential()
{
return (new RamRoleArnProvider($this))->get();
}
/**
* @return string
* @throws Exception
* @throws GuzzleException
*/
public function getAccessKeySecret()
{
return $this->getSessionCredential()->getAccessKeySecret();
}
/**
* @return string
* @throws Exception
* @throws GuzzleException
*/
public function getSecurityToken()
{
return $this->getSessionCredential()->getSecurityToken();
}
/**
* @return string
* @throws Exception
* @throws GuzzleException
*/
public function getExpiration()
{
return $this->getSessionCredential()->getExpiration();
}
}

View File

@@ -0,0 +1,37 @@
<?php
namespace AlibabaCloud\Credentials\Request;
use AlibabaCloud\Credentials\Providers\Provider;
use AlibabaCloud\Credentials\RamRoleArnCredential;
use AlibabaCloud\Credentials\Signature\ShaHmac1Signature;
/**
* Retrieving assume role credentials.
*/
class AssumeRole extends Request
{
/**
* AssumeRole constructor.
*
* @param RamRoleArnCredential $arnCredential
*/
public function __construct(RamRoleArnCredential $arnCredential)
{
parent::__construct();
$this->signature = new ShaHmac1Signature();
$this->credential = $arnCredential;
$this->uri = $this->uri->withHost('sts.aliyuncs.com');
$this->options['verify'] = false;
$this->options['query']['RoleArn'] = $arnCredential->getRoleArn();
$this->options['query']['RoleSessionName'] = $arnCredential->getRoleSessionName();
$this->options['query']['DurationSeconds'] = Provider::DURATION_SECONDS;
$this->options['query']['AccessKeyId'] = $this->credential->getOriginalAccessKeyId();
$this->options['query']['Version'] = '2015-04-01';
$this->options['query']['Action'] = 'AssumeRole';
$this->options['query']['RegionId'] = 'cn-hangzhou';
if ($arnCredential->getPolicy()) {
$this->options['query']['Policy'] = $arnCredential->getPolicy();
}
}
}

View File

@@ -0,0 +1,33 @@
<?php
namespace AlibabaCloud\Credentials\Request;
use AlibabaCloud\Credentials\Providers\Provider;
use AlibabaCloud\Credentials\RsaKeyPairCredential;
use AlibabaCloud\Credentials\Signature\ShaHmac256WithRsaSignature;
/**
* Use the RSA key pair to complete the authentication (supported only on Japanese site)
*/
class GenerateSessionAccessKey extends Request
{
/**
* GenerateSessionAccessKey constructor.
*
* @param RsaKeyPairCredential $credential
*/
public function __construct(RsaKeyPairCredential $credential)
{
parent::__construct();
$this->signature = new ShaHmac256WithRsaSignature();
$this->credential = $credential;
$this->uri = $this->uri->withHost('sts.ap-northeast-1.aliyuncs.com');
$this->options['verify'] = false;
$this->options['query']['Version'] = '2015-04-01';
$this->options['query']['Action'] = 'GenerateSessionAccessKey';
$this->options['query']['RegionId'] = 'cn-hangzhou';
$this->options['query']['AccessKeyId'] = $credential->getPublicKeyId();
$this->options['query']['PublicKeyId'] = $credential->getPublicKeyId();
$this->options['query']['DurationSeconds'] = Provider::DURATION_SECONDS;
}
}

View File

@@ -0,0 +1,155 @@
<?php
namespace AlibabaCloud\Credentials\Request;
use AlibabaCloud\Credentials\Credentials;
use AlibabaCloud\Credentials\EcsRamRoleCredential;
use AlibabaCloud\Credentials\Helper;
use AlibabaCloud\Credentials\RamRoleArnCredential;
use AlibabaCloud\Credentials\Signature\ShaHmac1Signature;
use AlibabaCloud\Credentials\Signature\ShaHmac256WithRsaSignature;
use Exception;
use GuzzleHttp\Client;
use GuzzleHttp\HandlerStack;
use GuzzleHttp\Middleware;
use GuzzleHttp\Psr7\Uri;
use AlibabaCloud\Tea\Response;
use Psr\Http\Message\ResponseInterface;
/**
* RESTful RPC Request.
*/
class Request
{
/**
* Request Connect Timeout
*/
const CONNECT_TIMEOUT = 5;
/**
* Request Timeout
*/
const TIMEOUT = 10;
/**
* @var array
*/
private static $config = [];
/**
* @var array
*/
public $options = [];
/**
* @var Uri
*/
public $uri;
/**
* @var EcsRamRoleCredential|RamRoleArnCredential
*/
protected $credential;
/**
* @var ShaHmac256WithRsaSignature|ShaHmac1Signature
*/
protected $signature;
/**
* Request constructor.
*/
public function __construct()
{
$this->uri = (new Uri())->withScheme('https');
$this->options['http_errors'] = false;
$this->options['connect_timeout'] = self::CONNECT_TIMEOUT;
$this->options['timeout'] = self::TIMEOUT;
// Turn on debug mode based on environment variable.
if (strtolower(Helper::env('DEBUG')) === 'sdk') {
$this->options['debug'] = true;
}
}
/**
* @return ResponseInterface
* @throws Exception
*/
public function request()
{
$this->options['query']['Format'] = 'JSON';
$this->options['query']['SignatureMethod'] = $this->signature->getMethod();
$this->options['query']['SignatureVersion'] = $this->signature->getVersion();
$this->options['query']['SignatureNonce'] = self::uuid(json_encode($this->options['query']));
$this->options['query']['Timestamp'] = gmdate('Y-m-d\TH:i:s\Z');
$this->options['query']['Signature'] = $this->signature->sign(
self::signString('GET', $this->options['query']),
$this->credential->getOriginalAccessKeySecret() . '&'
);
return self::createClient()->request('GET', (string)$this->uri, $this->options);
}
/**
* @param string $salt
*
* @return string
*/
public static function uuid($salt)
{
return md5($salt . uniqid(md5(microtime(true)), true));
}
/**
* @param string $method
* @param array $parameters
*
* @return string
*/
public static function signString($method, array $parameters)
{
ksort($parameters);
$canonicalized = '';
foreach ($parameters as $key => $value) {
$canonicalized .= '&' . self::percentEncode($key) . '=' . self::percentEncode($value);
}
return $method . '&%2F&' . self::percentEncode(substr($canonicalized, 1));
}
/**
* @param string $string
*
* @return null|string|string[]
*/
private static function percentEncode($string)
{
$result = rawurlencode($string);
$result = str_replace(['+', '*'], ['%20', '%2A'], $result);
$result = preg_replace('/%7E/', '~', $result);
return $result;
}
/**
* @return Client
* @throws Exception
*/
public static function createClient()
{
if (Credentials::hasMock()) {
$stack = HandlerStack::create(Credentials::getMock());
} else {
$stack = HandlerStack::create();
}
$stack->push(Middleware::mapResponse(static function (ResponseInterface $response) {
return new Response($response);
}));
self::$config['handler'] = $stack;
return new Client(self::$config);
}
}

View File

@@ -0,0 +1,158 @@
<?php
namespace AlibabaCloud\Credentials;
use AlibabaCloud\Credentials\Providers\RsaKeyPairProvider;
use AlibabaCloud\Credentials\Signature\ShaHmac1Signature;
use Exception;
use GuzzleHttp\Exception\GuzzleException;
use InvalidArgumentException;
/**
* Use the RSA key pair to complete the authentication (supported only on Japanese site)
*/
class RsaKeyPairCredential implements CredentialsInterface
{
/**
* @var string
*/
private $publicKeyId;
/**
* @var string
*/
private $privateKey;
/**
* @var array
*/
private $config;
/**
* RsaKeyPairCredential constructor.
*
* @param string $public_key_id
* @param string $private_key_file
* @param array $config
*/
public function __construct($public_key_id, $private_key_file, array $config = [])
{
Filter::publicKeyId($public_key_id);
Filter::privateKeyFile($private_key_file);
$this->publicKeyId = $public_key_id;
$this->config = $config;
try {
$this->privateKey = file_get_contents($private_key_file);
} catch (Exception $exception) {
throw new InvalidArgumentException($exception->getMessage());
}
}
/**
* @return array
*/
public function getConfig()
{
return $this->config;
}
/**
* @return string
*/
public function getOriginalAccessKeyId()
{
return $this->getPublicKeyId();
}
/**
* @return string
*/
public function getPublicKeyId()
{
return $this->publicKeyId;
}
/**
* @return string
*/
public function getOriginalAccessKeySecret()
{
return $this->getPrivateKey();
}
/**
* @return mixed
*/
public function getPrivateKey()
{
return $this->privateKey;
}
/**
* @return string
*/
public function __toString()
{
return "publicKeyId#$this->publicKeyId";
}
/**
* @return ShaHmac1Signature
*/
public function getSignature()
{
return new ShaHmac1Signature();
}
/**
* @return string
* @throws Exception
* @throws GuzzleException
*/
public function getAccessKeyId()
{
return $this->getSessionCredential()->getAccessKeyId();
}
/**
* @return StsCredential
* @throws Exception
* @throws GuzzleException
*/
protected function getSessionCredential()
{
return (new RsaKeyPairProvider($this))->get();
}
/**
* @return string
* @throws Exception
* @throws GuzzleException
*/
public function getAccessKeySecret()
{
return $this->getSessionCredential()->getAccessKeySecret();
}
/**
* @return string
* @throws Exception
* @throws GuzzleException
*/
public function getSecurityToken()
{
return $this->getSessionCredential()->getSecurityToken();
}
/**
* @return int
* @throws Exception
* @throws GuzzleException
*/
public function getExpiration()
{
return $this->getSessionCredential()->getExpiration();
}
}

View File

@@ -0,0 +1,47 @@
<?php
namespace AlibabaCloud\Credentials\Signature;
/**
* Class BearerTokenSignature
*
* @package AlibabaCloud\Credentials\Signature
*/
class BearerTokenSignature implements SignatureInterface
{
/**
* @return string
*/
public function getMethod()
{
return '';
}
/**
* @return string
*/
public function getType()
{
return 'BEARERTOKEN';
}
/**
* @return string
*/
public function getVersion()
{
return '1.0';
}
/**
* @param string $string
* @param string $accessKeySecret
*
* @return string
*/
public function sign($string, $accessKeySecret)
{
return '';
}
}

View File

@@ -0,0 +1,47 @@
<?php
namespace AlibabaCloud\Credentials\Signature;
/**
* Class ShaHmac1Signature
*
* @package AlibabaCloud\Credentials\Signature
*/
class ShaHmac1Signature implements SignatureInterface
{
/**
* @return string
*/
public function getMethod()
{
return 'HMAC-SHA1';
}
/**
* @return string
*/
public function getType()
{
return '';
}
/**
* @return string
*/
public function getVersion()
{
return '1.0';
}
/**
* @param string $string
* @param string $accessKeySecret
*
* @return string
*/
public function sign($string, $accessKeySecret)
{
return base64_encode(hash_hmac('sha1', $string, $accessKeySecret, true));
}
}

View File

@@ -0,0 +1,47 @@
<?php
namespace AlibabaCloud\Credentials\Signature;
/**
* Class ShaHmac256Signature
*
* @package AlibabaCloud\Credentials\Signature
*/
class ShaHmac256Signature implements SignatureInterface
{
/**
* @return string
*/
public function getMethod()
{
return 'HMAC-SHA256';
}
/**
* @return string
*/
public function getType()
{
return '';
}
/**
* @return string
*/
public function getVersion()
{
return '1.0';
}
/**
* @param string $string
* @param string $accessKeySecret
*
* @return string
*/
public function sign($string, $accessKeySecret)
{
return base64_encode(hash_hmac('sha256', $string, $accessKeySecret, true));
}
}

View File

@@ -0,0 +1,64 @@
<?php
namespace AlibabaCloud\Credentials\Signature;
use Exception;
use InvalidArgumentException;
/**
* Class ShaHmac256WithRsaSignature
*
* @package AlibabaCloud\Credentials\Signature
*/
class ShaHmac256WithRsaSignature implements SignatureInterface
{
/**
* @return string
*/
public function getMethod()
{
return 'SHA256withRSA';
}
/**
* @return string
*/
public function getType()
{
return 'PRIVATEKEY';
}
/**
* @return string
*/
public function getVersion()
{
return '1.0';
}
/**
* @param string $string
* @param string $privateKey
*
* @return string
*/
public function sign($string, $privateKey)
{
$binarySignature = '';
try {
openssl_sign(
$string,
$binarySignature,
$privateKey,
\OPENSSL_ALGO_SHA256
);
} catch (Exception $exception) {
throw new InvalidArgumentException(
$exception->getMessage()
);
}
return base64_encode($binarySignature);
}
}

View File

@@ -0,0 +1,34 @@
<?php
namespace AlibabaCloud\Credentials\Signature;
/**
* Interface SignatureInterface
*
* @package AlibabaCloud\Credentials\Signature
*/
interface SignatureInterface
{
/**
* @return string
*/
public function getMethod();
/**
* @return string
*/
public function getVersion();
/**
* @param string $string
* @param string $accessKeySecret
*
* @return string
*/
public function sign($string, $accessKeySecret);
/**
* @return string
*/
public function getType();
}

View File

@@ -0,0 +1,98 @@
<?php
namespace AlibabaCloud\Credentials;
use AlibabaCloud\Credentials\Signature\ShaHmac1Signature;
/**
* Use the STS Token to complete the authentication.
*/
class StsCredential implements CredentialsInterface
{
/**
* @var string
*/
private $accessKeyId;
/**
* @var string
*/
private $accessKeySecret;
/**
* @var string
*/
private $securityToken;
/**
* @var int
*/
private $expiration;
/**
* StsCredential constructor.
*
* @param string $access_key_id Access key ID
* @param string $access_key_secret Access Key Secret
* @param int $expiration
* @param string $security_token Security Token
*/
public function __construct($access_key_id, $access_key_secret, $expiration, $security_token = '')
{
Filter::accessKey($access_key_id, $access_key_secret);
Filter::expiration($expiration);
$this->accessKeyId = $access_key_id;
$this->accessKeySecret = $access_key_secret;
$this->expiration = $expiration;
$this->securityToken = $security_token;
}
/**
* @return int
*/
public function getExpiration()
{
return $this->expiration;
}
/**
* @return string
*/
public function getAccessKeyId()
{
return $this->accessKeyId;
}
/**
* @return string
*/
public function getAccessKeySecret()
{
return $this->accessKeySecret;
}
/**
* @return string
*/
public function getSecurityToken()
{
return $this->securityToken;
}
/**
* @return string
*/
public function __toString()
{
return "$this->accessKeyId#$this->accessKeySecret#$this->securityToken";
}
/**
* @return ShaHmac1Signature
*/
public function getSignature()
{
return new ShaHmac1Signature();
}
}