Ir a la última revisión | Autoría | Comparar con el anterior | Ultima modificación | Ver Log |
<?phpnamespace Aws\Credentials;use Aws;use Aws\Api\DateTimeResult;use Aws\CacheInterface;use Aws\Exception\CredentialsException;use Aws\Sts\StsClient;use GuzzleHttp\Promise;/*** Credential providers are functions that accept no arguments and return a* promise that is fulfilled with an {@see \Aws\Credentials\CredentialsInterface}* or rejected with an {@see \Aws\Exception\CredentialsException}.** <code>* use Aws\Credentials\CredentialProvider;* $provider = CredentialProvider::defaultProvider();* // Returns a CredentialsInterface or throws.* $creds = $provider()->wait();* </code>** Credential providers can be composed to create credentials using conditional* logic that can create different credentials in different environments. You* can compose multiple providers into a single provider using* {@see Aws\Credentials\CredentialProvider::chain}. This function accepts* providers as variadic arguments and returns a new function that will invoke* each provider until a successful set of credentials is returned.** <code>* // First try an INI file at this location.* $a = CredentialProvider::ini(null, '/path/to/file.ini');* // Then try an INI file at this location.* $b = CredentialProvider::ini(null, '/path/to/other-file.ini');* // Then try loading from environment variables.* $c = CredentialProvider::env();* // Combine the three providers together.* $composed = CredentialProvider::chain($a, $b, $c);* // Returns a promise that is fulfilled with credentials or throws.* $promise = $composed();* // Wait on the credentials to resolve.* $creds = $promise->wait();* </code>*/class CredentialProvider{const ENV_ARN = 'AWS_ROLE_ARN';const ENV_KEY = 'AWS_ACCESS_KEY_ID';const ENV_PROFILE = 'AWS_PROFILE';const ENV_ROLE_SESSION_NAME = 'AWS_ROLE_SESSION_NAME';const ENV_SECRET = 'AWS_SECRET_ACCESS_KEY';const ENV_SESSION = 'AWS_SESSION_TOKEN';const ENV_TOKEN_FILE = 'AWS_WEB_IDENTITY_TOKEN_FILE';const ENV_SHARED_CREDENTIALS_FILE = 'AWS_SHARED_CREDENTIALS_FILE';/*** Create a default credential provider that* first checks for environment variables,* then checks for assumed role via web identity,* then checks for cached SSO credentials from the CLI,* then check for credential_process in the "default" profile in ~/.aws/credentials,* then checks for the "default" profile in ~/.aws/credentials,* then for credential_process in the "default profile" profile in ~/.aws/config,* then checks for "profile default" profile in ~/.aws/config (which is* the default profile of AWS CLI),* then tries to make a GET Request to fetch credentials if ECS environment variable is presented,* finally checks for EC2 instance profile credentials.** This provider is automatically wrapped in a memoize function that caches* previously provided credentials.** @param array $config Optional array of ecs/instance profile credentials* provider options.** @return callable*/public static function defaultProvider(array $config = []){$cacheable = ['web_identity','sso','process_credentials','process_config','ecs','instance'];$profileName = getenv(self::ENV_PROFILE) ?: 'default';$defaultChain = ['env' => self::env(),'web_identity' => self::assumeRoleWithWebIdentityCredentialProvider($config),];if (!isset($config['use_aws_shared_config_files'])|| $config['use_aws_shared_config_files'] !== false) {$defaultChain['sso'] = self::sso($profileName,self::getHomeDir() . '/.aws/config',$config);$defaultChain['process_credentials'] = self::process();$defaultChain['ini'] = self::ini();$defaultChain['process_config'] = self::process('profile ' . $profileName,self::getHomeDir() . '/.aws/config');$defaultChain['ini_config'] = self::ini('profile '. $profileName,self::getHomeDir() . '/.aws/config');}if (self::shouldUseEcs()) {$defaultChain['ecs'] = self::ecsCredentials($config);} else {$defaultChain['instance'] = self::instanceProfile($config);}if (isset($config['credentials'])&& $config['credentials'] instanceof CacheInterface) {foreach ($cacheable as $provider) {if (isset($defaultChain[$provider])) {$defaultChain[$provider] = self::cache($defaultChain[$provider],$config['credentials'],'aws_cached_' . $provider . '_credentials');}}}return self::memoize(call_user_func_array([CredentialProvider::class, 'chain'],array_values($defaultChain)));}/*** Create a credential provider function from a set of static credentials.** @param CredentialsInterface $creds** @return callable*/public static function fromCredentials(CredentialsInterface $creds){$promise = Promise\Create::promiseFor($creds);return function () use ($promise) {return $promise;};}/*** Creates an aggregate credentials provider that invokes the provided* variadic providers one after the other until a provider returns* credentials.** @return callable*/public static function chain(){$links = func_get_args();if (empty($links)) {throw new \InvalidArgumentException('No providers in chain');}return function ($previousCreds = null) use ($links) {/** @var callable $parent */$parent = array_shift($links);$promise = $parent();while ($next = array_shift($links)) {if ($next instanceof InstanceProfileProvider&& $previousCreds instanceof Credentials) {$promise = $promise->otherwise(function () use ($next, $previousCreds) {return $next($previousCreds);});} else {$promise = $promise->otherwise($next);}}return $promise;};}/*** Wraps a credential provider and caches previously provided credentials.** Ensures that cached credentials are refreshed when they expire.** @param callable $provider Credentials provider function to wrap.** @return callable*/public static function memoize(callable $provider){return function () use ($provider) {static $result;static $isConstant;// Constant credentials will be returned constantly.if ($isConstant) {return $result;}// Create the initial promise that will be used as the cached value// until it expires.if (null === $result) {$result = $provider();}// Return credentials that could expire and refresh when needed.return $result->then(function (CredentialsInterface $creds) use ($provider, &$isConstant, &$result) {// Determine if these are constant credentials.if (!$creds->getExpiration()) {$isConstant = true;return $creds;}// Refresh expired credentials.if (!$creds->isExpired()) {return $creds;}// Refresh the result and forward the promise.return $result = $provider($creds);})->otherwise(function($reason) use (&$result) {// Cleanup rejected promise.$result = null;return new Promise\RejectedPromise($reason);});};}/*** Wraps a credential provider and saves provided credentials in an* instance of Aws\CacheInterface. Forwards calls when no credentials found* in cache and updates cache with the results.** @param callable $provider Credentials provider function to wrap* @param CacheInterface $cache Cache to store credentials* @param string|null $cacheKey (optional) Cache key to use** @return callable*/public static function cache(callable $provider,CacheInterface $cache,$cacheKey = null) {$cacheKey = $cacheKey ?: 'aws_cached_credentials';return function () use ($provider, $cache, $cacheKey) {$found = $cache->get($cacheKey);if ($found instanceof CredentialsInterface && !$found->isExpired()) {return Promise\Create::promiseFor($found);}return $provider()->then(function (CredentialsInterface $creds) use ($cache,$cacheKey) {$cache->set($cacheKey,$creds,null === $creds->getExpiration() ?0 : $creds->getExpiration() - time());return $creds;});};}/*** Provider that creates credentials from environment variables* AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, and AWS_SESSION_TOKEN.** @return callable*/public static function env(){return function () {// Use credentials from environment variables, if available$key = getenv(self::ENV_KEY);$secret = getenv(self::ENV_SECRET);if ($key && $secret) {return Promise\Create::promiseFor(new Credentials($key, $secret, getenv(self::ENV_SESSION) ?: NULL));}return self::reject('Could not find environment variable '. 'credentials in ' . self::ENV_KEY . '/' . self::ENV_SECRET);};}/*** Credential provider that creates credentials using instance profile* credentials.** @param array $config Array of configuration data.** @return InstanceProfileProvider* @see Aws\Credentials\InstanceProfileProvider for $config details.*/public static function instanceProfile(array $config = []){return new InstanceProfileProvider($config);}/*** Credential provider that retrieves cached SSO credentials from the CLI** @return callable*/public static function sso($ssoProfileName = 'default',$filename = null,$config = []) {$filename = $filename ?: (self::getHomeDir() . '/.aws/config');return function () use ($ssoProfileName, $filename, $config) {if (!@is_readable($filename)) {return self::reject("Cannot read credentials from $filename");}$profiles = self::loadProfiles($filename);if (isset($profiles[$ssoProfileName])) {$ssoProfile = $profiles[$ssoProfileName];} elseif (isset($profiles['profile ' . $ssoProfileName])) {$ssoProfileName = 'profile ' . $ssoProfileName;$ssoProfile = $profiles[$ssoProfileName];} else {return self::reject("Profile {$ssoProfileName} does not exist in {$filename}.");}if (!empty($ssoProfile['sso_session'])) {return CredentialProvider::getSsoCredentials($profiles, $ssoProfileName, $filename, $config);} else {return CredentialProvider::getSsoCredentialsLegacy($profiles, $ssoProfileName, $filename, $config);}};}/*** Credential provider that creates credentials using* ecs credentials by a GET request, whose uri is specified* by environment variable** @param array $config Array of configuration data.** @return EcsCredentialProvider* @see Aws\Credentials\EcsCredentialProvider for $config details.*/public static function ecsCredentials(array $config = []){return new EcsCredentialProvider($config);}/*** Credential provider that creates credentials using assume role** @param array $config Array of configuration data* @return callable* @see Aws\Credentials\AssumeRoleCredentialProvider for $config details.*/public static function assumeRole(array $config=[]){return new AssumeRoleCredentialProvider($config);}/*** Credential provider that creates credentials by assuming role from a* Web Identity Token** @param array $config Array of configuration data* @return callable* @see Aws\Credentials\AssumeRoleWithWebIdentityCredentialProvider for* $config details.*/public static function assumeRoleWithWebIdentityCredentialProvider(array $config = []){return function () use ($config) {$arnFromEnv = getenv(self::ENV_ARN);$tokenFromEnv = getenv(self::ENV_TOKEN_FILE);$stsClient = isset($config['stsClient'])? $config['stsClient']: null;$region = isset($config['region'])? $config['region']: null;if ($tokenFromEnv && $arnFromEnv) {$sessionName = getenv(self::ENV_ROLE_SESSION_NAME)? getenv(self::ENV_ROLE_SESSION_NAME): null;$provider = new AssumeRoleWithWebIdentityCredentialProvider(['RoleArn' => $arnFromEnv,'WebIdentityTokenFile' => $tokenFromEnv,'SessionName' => $sessionName,'client' => $stsClient,'region' => $region]);return $provider();}$profileName = getenv(self::ENV_PROFILE) ?: 'default';if (isset($config['filename'])) {$profiles = self::loadProfiles($config['filename']);} else {$profiles = self::loadDefaultProfiles();}if (isset($profiles[$profileName])) {$profile = $profiles[$profileName];if (isset($profile['region'])) {$region = $profile['region'];}if (isset($profile['web_identity_token_file'])&& isset($profile['role_arn'])) {$sessionName = isset($profile['role_session_name'])? $profile['role_session_name']: null;$provider = new AssumeRoleWithWebIdentityCredentialProvider(['RoleArn' => $profile['role_arn'],'WebIdentityTokenFile' => $profile['web_identity_token_file'],'SessionName' => $sessionName,'client' => $stsClient,'region' => $region]);return $provider();}} else {return self::reject("Unknown profile: $profileName");}return self::reject("No RoleArn or WebIdentityTokenFile specified");};}/*** Credentials provider that creates credentials using an ini file stored* in the current user's home directory. A source can be provided* in this file for assuming a role using the credential_source config option.** @param string|null $profile Profile to use. If not specified will use* the "default" profile in "~/.aws/credentials".* @param string|null $filename If provided, uses a custom filename rather* than looking in the home directory.* @param array|null $config If provided, may contain the following:* preferStaticCredentials: If true, prefer static* credentials to role_arn if both are present* disableAssumeRole: If true, disable support for* roles that assume an IAM role. If true and role profile* is selected, an error is raised.* stsClient: StsClient used to assume role specified in profile** @return callable*/public static function ini($profile = null, $filename = null, array $config = []){$filename = self::getFileName($filename);$profile = $profile ?: (getenv(self::ENV_PROFILE) ?: 'default');return function () use ($profile, $filename, $config) {$preferStaticCredentials = isset($config['preferStaticCredentials'])? $config['preferStaticCredentials']: false;$disableAssumeRole = isset($config['disableAssumeRole'])? $config['disableAssumeRole']: false;$stsClient = isset($config['stsClient']) ? $config['stsClient'] : null;if (!@is_readable($filename)) {return self::reject("Cannot read credentials from $filename");}$data = self::loadProfiles($filename);if ($data === false) {return self::reject("Invalid credentials file: $filename");}if (!isset($data[$profile])) {return self::reject("'$profile' not found in credentials file");}/*In the CLI, the presence of both a role_arn and static credentials havedifferent meanings depending on how many profiles have been visited. Forthe first profile processed, role_arn takes precedence over any staticcredentials, but for all subsequent profiles, static credentials areused if present, and only in their absence will the profile'ssource_profile and role_arn keys be used to load another set ofcredentials. This bool is intended to yield compatible behaviour in thissdk.*/$preferStaticCredentialsToRoleArn = ($preferStaticCredentials&& isset($data[$profile]['aws_access_key_id'])&& isset($data[$profile]['aws_secret_access_key']));if (isset($data[$profile]['role_arn'])&& !$preferStaticCredentialsToRoleArn) {if ($disableAssumeRole) {return self::reject("Role assumption profiles are disabled. ". "Failed to load profile " . $profile);}return self::loadRoleProfile($data,$profile,$filename,$stsClient,$config);}if (!isset($data[$profile]['aws_access_key_id'])|| !isset($data[$profile]['aws_secret_access_key'])) {return self::reject("No credentials present in INI profile ". "'$profile' ($filename)");}if (empty($data[$profile]['aws_session_token'])) {$data[$profile]['aws_session_token']= isset($data[$profile]['aws_security_token'])? $data[$profile]['aws_security_token']: null;}return Promise\Create::promiseFor(new Credentials($data[$profile]['aws_access_key_id'],$data[$profile]['aws_secret_access_key'],$data[$profile]['aws_session_token']));};}/*** Credentials provider that creates credentials using a process configured in* ini file stored in the current user's home directory.** @param string|null $profile Profile to use. If not specified will use* the "default" profile in "~/.aws/credentials".* @param string|null $filename If provided, uses a custom filename rather* than looking in the home directory.** @return callable*/public static function process($profile = null, $filename = null){$filename = self::getFileName($filename);$profile = $profile ?: (getenv(self::ENV_PROFILE) ?: 'default');return function () use ($profile, $filename) {if (!@is_readable($filename)) {return self::reject("Cannot read process credentials from $filename");}$data = \Aws\parse_ini_file($filename, true, INI_SCANNER_RAW);if ($data === false) {return self::reject("Invalid credentials file: $filename");}if (!isset($data[$profile])) {return self::reject("'$profile' not found in credentials file");}if (!isset($data[$profile]['credential_process'])) {return self::reject("No credential_process present in INI profile ". "'$profile' ($filename)");}$credentialProcess = $data[$profile]['credential_process'];$json = shell_exec($credentialProcess);$processData = json_decode($json, true);// Only support version 1if (isset($processData['Version'])) {if ($processData['Version'] !== 1) {return self::reject("credential_process does not return Version == 1");}}if (!isset($processData['AccessKeyId'])|| !isset($processData['SecretAccessKey'])){return self::reject("credential_process does not return valid credentials");}if (isset($processData['Expiration'])) {try {$expiration = new DateTimeResult($processData['Expiration']);} catch (\Exception $e) {return self::reject("credential_process returned invalid expiration");}$now = new DateTimeResult();if ($expiration < $now) {return self::reject("credential_process returned expired credentials");}$expires = $expiration->getTimestamp();} else {$expires = null;}if (empty($processData['SessionToken'])) {$processData['SessionToken'] = null;}return Promise\Create::promiseFor(new Credentials($processData['AccessKeyId'],$processData['SecretAccessKey'],$processData['SessionToken'],$expires));};}/*** Assumes role for profile that includes role_arn** @return callable*/private static function loadRoleProfile($profiles,$profileName,$filename,$stsClient,$config = []) {$roleProfile = $profiles[$profileName];$roleArn = isset($roleProfile['role_arn']) ? $roleProfile['role_arn'] : '';$roleSessionName = isset($roleProfile['role_session_name'])? $roleProfile['role_session_name']: 'aws-sdk-php-' . round(microtime(true) * 1000);if (empty($roleProfile['source_profile'])== empty($roleProfile['credential_source'])) {return self::reject("Either source_profile or credential_source must be set " ."using profile " . $profileName . ", but not both.");}$sourceProfileName = "";if (!empty($roleProfile['source_profile'])) {$sourceProfileName = $roleProfile['source_profile'];if (!isset($profiles[$sourceProfileName])) {return self::reject("source_profile " . $sourceProfileName. " using profile " . $profileName . " does not exist");}if (isset($config['visited_profiles']) &&in_array($roleProfile['source_profile'], $config['visited_profiles'])) {return self::reject("Circular source_profile reference found.");}$config['visited_profiles'] [] = $roleProfile['source_profile'];} else {if (empty($roleArn)) {return self::reject("A role_arn must be provided with credential_source in " ."file {$filename} under profile {$profileName} ");}}if (empty($stsClient)) {$sourceRegion = isset($profiles[$sourceProfileName]['region'])? $profiles[$sourceProfileName]['region']: 'us-east-1';$config['preferStaticCredentials'] = true;$sourceCredentials = null;if (!empty($roleProfile['source_profile'])){$sourceCredentials = call_user_func(CredentialProvider::ini($sourceProfileName, $filename, $config))->wait();} else {$sourceCredentials = self::getCredentialsFromSource($profileName,$filename);}$stsClient = new StsClient(['credentials' => $sourceCredentials,'region' => $sourceRegion,'version' => '2011-06-15',]);}$result = $stsClient->assumeRole(['RoleArn' => $roleArn,'RoleSessionName' => $roleSessionName]);$credentials = $stsClient->createCredentials($result);return Promise\Create::promiseFor($credentials);}/*** Gets the environment's HOME directory if available.** @return null|string*/private static function getHomeDir(){// On Linux/Unix-like systems, use the HOME environment variableif ($homeDir = getenv('HOME')) {return $homeDir;}// Get the HOMEDRIVE and HOMEPATH values for Windows hosts$homeDrive = getenv('HOMEDRIVE');$homePath = getenv('HOMEPATH');return ($homeDrive && $homePath) ? $homeDrive . $homePath : null;}/*** Gets profiles from specified $filename, or default ini files.*/private static function loadProfiles($filename){$profileData = \Aws\parse_ini_file($filename, true, INI_SCANNER_RAW);// If loading .aws/credentials, also load .aws/config when AWS_SDK_LOAD_NONDEFAULT_CONFIG is setif ($filename === self::getHomeDir() . '/.aws/credentials'&& getenv('AWS_SDK_LOAD_NONDEFAULT_CONFIG')) {$configFilename = self::getHomeDir() . '/.aws/config';$configProfileData = \Aws\parse_ini_file($configFilename, true, INI_SCANNER_RAW);foreach ($configProfileData as $name => $profile) {// standardize config profile names$name = str_replace('profile ', '', $name);if (!isset($profileData[$name])) {$profileData[$name] = $profile;}}}return $profileData;}/*** Gets profiles from ~/.aws/credentials and ~/.aws/config ini files*/private static function loadDefaultProfiles() {$profiles = [];$credFile = self::getHomeDir() . '/.aws/credentials';$configFile = self::getHomeDir() . '/.aws/config';if (file_exists($credFile)) {$profiles = \Aws\parse_ini_file($credFile, true, INI_SCANNER_RAW);}if (file_exists($configFile)) {$configProfileData = \Aws\parse_ini_file($configFile, true, INI_SCANNER_RAW);foreach ($configProfileData as $name => $profile) {// standardize config profile names$name = str_replace('profile ', '', $name);if (!isset($profiles[$name])) {$profiles[$name] = $profile;}}}return $profiles;}public static function getCredentialsFromSource($profileName = '',$filename = '',$config = []) {$data = self::loadProfiles($filename);$credentialSource = !empty($data[$profileName]['credential_source'])? $data[$profileName]['credential_source']: null;$credentialsPromise = null;switch ($credentialSource) {case 'Environment':$credentialsPromise = self::env();break;case 'Ec2InstanceMetadata':$credentialsPromise = self::instanceProfile($config);break;case 'EcsContainer':$credentialsPromise = self::ecsCredentials($config);break;default:throw new CredentialsException("Invalid credential_source found in config file: {$credentialSource}. Valid inputs ". "include Environment, Ec2InstanceMetadata, and EcsContainer.");}$credentialsResult = null;try {$credentialsResult = $credentialsPromise()->wait();} catch (\Exception $reason) {return self::reject("Unable to successfully retrieve credentials from the source specified in the". " credentials file: {$credentialSource}; failure message was: ". $reason->getMessage());}return function () use ($credentialsResult) {return Promise\Create::promiseFor($credentialsResult);};}private static function reject($msg){return new Promise\RejectedPromise(new CredentialsException($msg));}/*** @param $filename* @return string*/private static function getFileName($filename){if (!isset($filename)) {$filename = getenv(self::ENV_SHARED_CREDENTIALS_FILE) ?:(self::getHomeDir() . '/.aws/credentials');}return $filename;}/*** @return boolean*/public static function shouldUseEcs(){//Check for relative uri. if not, then full uri.//fall back to server for each as getenv is not thread-safe.return !empty(getenv(EcsCredentialProvider::ENV_URI))|| !empty($_SERVER[EcsCredentialProvider::ENV_URI])|| !empty(getenv(EcsCredentialProvider::ENV_FULL_URI))|| !empty($_SERVER[EcsCredentialProvider::ENV_FULL_URI]);}/*** @param $profiles* @param $ssoProfileName* @param $filename* @param $config* @return Promise\PromiseInterface*/private static function getSsoCredentials($profiles, $ssoProfileName, $filename, $config){if (empty($config['ssoOidcClient'])) {$ssoProfile = $profiles[$ssoProfileName];$sessionName = $ssoProfile['sso_session'];if (empty($profiles['sso-session ' . $sessionName])) {return self::reject("Could not find sso-session {$sessionName} in {$filename}");}$ssoSession = $profiles['sso-session ' . $ssoProfile['sso_session']];$ssoOidcClient = new Aws\SSOOIDC\SSOOIDCClient(['region' => $ssoSession['sso_region'],'version' => '2019-06-10','credentials' => false]);} else {$ssoOidcClient = $config['ssoClient'];}$tokenPromise = new Aws\Token\SsoTokenProvider($ssoProfileName,$filename,$ssoOidcClient);$token = $tokenPromise()->wait();$ssoCredentials = CredentialProvider::getCredentialsFromSsoService($ssoProfile,$ssoSession['sso_region'],$token->getToken(),$config);$expiration = $ssoCredentials['expiration'];return Promise\Create::promiseFor(new Credentials($ssoCredentials['accessKeyId'],$ssoCredentials['secretAccessKey'],$ssoCredentials['sessionToken'],$expiration));}/*** @param $profiles* @param $ssoProfileName* @param $filename* @param $config* @return Promise\PromiseInterface*/private static function getSsoCredentialsLegacy($profiles, $ssoProfileName, $filename, $config){$ssoProfile = $profiles[$ssoProfileName];if (empty($ssoProfile['sso_start_url'])|| empty($ssoProfile['sso_region'])|| empty($ssoProfile['sso_account_id'])|| empty($ssoProfile['sso_role_name'])) {return self::reject("Profile {$ssoProfileName} in {$filename} must contain the following keys: ". "sso_start_url, sso_region, sso_account_id, and sso_role_name.");}$tokenLocation = self::getHomeDir(). '/.aws/sso/cache/'. sha1($ssoProfile['sso_start_url']). ".json";if (!@is_readable($tokenLocation)) {return self::reject("Unable to read token file at $tokenLocation");}$tokenData = json_decode(file_get_contents($tokenLocation), true);if (empty($tokenData['accessToken']) || empty($tokenData['expiresAt'])) {return self::reject("Token file at {$tokenLocation} must contain an access token and an expiration");}try {$expiration = (new DateTimeResult($tokenData['expiresAt']))->getTimestamp();} catch (\Exception $e) {return self::reject("Cached SSO credentials returned an invalid expiration");}$now = time();if ($expiration < $now) {return self::reject("Cached SSO credentials returned expired credentials");}$ssoCredentials = CredentialProvider::getCredentialsFromSsoService($ssoProfile,$ssoProfile['sso_region'],$tokenData['accessToken'],$config);return Promise\Create::promiseFor(new Credentials($ssoCredentials['accessKeyId'],$ssoCredentials['secretAccessKey'],$ssoCredentials['sessionToken'],$expiration));}/*** @param array $ssoProfile* @param string $clientRegion* @param string $accessToken* @param array $config* @return array|null*/private static function getCredentialsFromSsoService($ssoProfile, $clientRegion, $accessToken, $config){if (empty($config['ssoClient'])) {$ssoClient = new Aws\SSO\SSOClient(['region' => $clientRegion,'version' => '2019-06-10','credentials' => false]);} else {$ssoClient = $config['ssoClient'];}$ssoResponse = $ssoClient->getRoleCredentials(['accessToken' => $accessToken,'accountId' => $ssoProfile['sso_account_id'],'roleName' => $ssoProfile['sso_role_name']]);$ssoCredentials = $ssoResponse['roleCredentials'];return $ssoCredentials;}}