summaryrefslogtreecommitdiff
path: root/vendor/aws/aws-sdk-php/src/Token/SsoTokenProvider.php
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/aws/aws-sdk-php/src/Token/SsoTokenProvider.php')
-rw-r--r--vendor/aws/aws-sdk-php/src/Token/SsoTokenProvider.php213
1 files changed, 213 insertions, 0 deletions
diff --git a/vendor/aws/aws-sdk-php/src/Token/SsoTokenProvider.php b/vendor/aws/aws-sdk-php/src/Token/SsoTokenProvider.php
new file mode 100644
index 0000000..7d8f4b4
--- /dev/null
+++ b/vendor/aws/aws-sdk-php/src/Token/SsoTokenProvider.php
@@ -0,0 +1,213 @@
+<?php
+namespace Aws\Token;
+
+use Aws\Exception\TokenException;
+use GuzzleHttp\Promise;
+
+/**
+ * Token that comes from the SSO provider
+ */
+class SsoTokenProvider implements RefreshableTokenProviderInterface
+{
+ use ParsesIniTrait;
+
+ const ENV_PROFILE = 'AWS_PROFILE';
+
+ private $ssoProfileName;
+ private $filename;
+ private $ssoOidcClient;
+
+ /**
+ * Constructs a new SSO token object, with the specified AWS
+ * token
+ *
+ * @param string $token Security token to use
+ * @param int $expires UNIX timestamp for when the token expires
+ */
+ public function __construct($ssoProfileName, $filename = null, $ssoOidcClient = null) {
+ $profileName = getenv(self::ENV_PROFILE) ?: 'default';
+ $this->ssoProfileName = !empty($ssoProfileName) ? $ssoProfileName : $profileName;
+ $this->filename = !empty($filename)
+ ? $filename :
+ self::getHomeDir() . '/.aws/config';
+ $this->ssoOidcClient = $ssoOidcClient;
+ }
+
+ /*
+ * Loads cached sso credentials
+ *
+ * @return PromiseInterface
+ */
+ public function __invoke()
+ {
+ return Promise\Coroutine::of(function () {
+ if (!@is_readable($this->filename)) {
+ throw new TokenException("Cannot read token from $this->filename");
+ }
+ $profiles = self::loadProfiles($this->filename);
+ if (!isset($profiles[$this->ssoProfileName])) {
+ throw new TokenException("Profile {$this->ssoProfileName} does not exist in {$this->filename}.");
+ }
+ $ssoProfile = $profiles[$this->ssoProfileName];
+ if (empty($ssoProfile['sso_session'])) {
+ throw new TokenException(
+ "Profile {$this->ssoProfileName} in {$this->filename} must contain an sso_session."
+ );
+ }
+
+ $sessionProfileName = 'sso-session ' . $ssoProfile['sso_session'];
+ if (empty($profiles[$sessionProfileName])) {
+ throw new TokenException(
+ "Profile {$this->ssoProfileName} does not exist in {$this->filename}"
+ );
+ }
+
+ $sessionProfileData = $profiles[$sessionProfileName];
+ if (empty($sessionProfileData['sso_start_url'])
+ || empty($sessionProfileData['sso_region'])
+ ) {
+ throw new TokenException(
+ "Profile {$this->ssoProfileName} in {$this->filename} must contain the following keys: "
+ . "sso_start_url and sso_region."
+ );
+ }
+
+ $tokenLocation = self::getTokenLocation($ssoProfile['sso_session']);
+ if (!@is_readable($tokenLocation)) {
+ throw new TokenException("Unable to read token file at $tokenLocation");
+ }
+ $tokenData = $this->getTokenData($tokenLocation);
+ $this->validateTokenData($tokenLocation, $tokenData);
+ yield new SsoToken(
+ $tokenData['accessToken'],
+ $tokenData['expiresAt'],
+ isset($tokenData['refreshToken']) ? $tokenData['refreshToken'] : null,
+ isset($tokenData['clientId']) ? $tokenData['clientId'] : null,
+ isset($tokenData['clientSecret']) ? $tokenData['clientSecret'] : null,
+ isset($tokenData['registrationExpiresAt']) ? $tokenData['registrationExpiresAt'] : null,
+ isset($tokenData['region']) ? $tokenData['region'] : null,
+ isset($tokenData['startUrl']) ? $tokenData['startUrl'] : null
+ );
+ });
+ }
+
+ /**
+ * Refreshes the token
+ * @return mixed|null
+ */
+ public function refresh() {
+ try {
+ //try to reload from disk
+ $token = $this();
+ if (
+ $token instanceof SsoToken
+ && !$token->shouldAttemptRefresh()
+ ) {
+ return $token;
+ }
+ } finally {
+ //if reload from disk fails, try refreshing
+ $tokenLocation = self::getTokenLocation($this->ssoProfileName);
+ $tokenData = $this->getTokenData($tokenLocation);
+ if (
+ empty($this->ssoOidcClient)
+ || empty($tokenData['startUrl'])
+ ) {
+ throw new TokenException(
+ "Cannot refresh this token without an 'ssooidcClient' "
+ . "and a 'start_url'"
+ );
+ }
+ $response = $this->ssoOidcClient->createToken([
+ 'clientId' => $tokenData['clientId'],
+ 'clientSecret' => $tokenData['clientSecret'],
+ 'grantType' => 'refresh_token', // REQUIRED
+ 'refreshToken' => $tokenData['refreshToken'],
+ ]);
+ if ($response['@metadata']['statusCode'] == 200) {
+ $tokenData['accessToken'] = $response['accessToken'];
+ $tokenData['expiresAt'] = time () + $response['expiresIn'];
+ $tokenData['refreshToken'] = $response['refreshToken'];
+ $token = new SsoToken(
+ $tokenData['accessToken'],
+ $tokenData['expiresAt'],
+ $tokenData['refreshToken'],
+ isset($tokenData['clientId']) ? $tokenData['clientId'] : null,
+ isset($tokenData['clientSecret']) ? $tokenData['clientSecret'] : null,
+ isset($tokenData['registrationExpiresAt']) ? $tokenData['registrationExpiresAt'] : null,
+ isset($tokenData['region']) ? $tokenData['region'] : null,
+ isset($tokenData['startUrl']) ? $tokenData['startUrl'] : null );
+
+ $this->writeNewTokenDataToDisk($tokenData, $tokenLocation);
+
+ return $token;
+ }
+ }
+ }
+
+ public function shouldAttemptRefresh()
+ {
+ $tokenLocation = self::getTokenLocation($this->ssoProfileName);
+ $tokenData = $this->getTokenData($tokenLocation);
+ return strtotime("-10 minutes") >= strtotime($tokenData['expiresAt']);
+ }
+
+ /**
+ * @param $sso_session
+ * @return string
+ */
+ public static function getTokenLocation($sso_session)
+ {
+ return self::getHomeDir()
+ . '/.aws/sso/cache/'
+ . utf8_encode(sha1($sso_session))
+ . ".json";
+ }
+
+ /**
+ * @param $tokenLocation
+ * @return array
+ */
+ function getTokenData($tokenLocation)
+ {
+ return json_decode(file_get_contents($tokenLocation), true);
+ }
+
+ /**
+ * @param $tokenData
+ * @param $tokenLocation
+ * @return mixed
+ */
+ private function validateTokenData($tokenLocation, $tokenData)
+ {
+ if (empty($tokenData['accessToken']) || empty($tokenData['expiresAt'])) {
+ throw new TokenException(
+ "Token file at {$tokenLocation} must contain an access token and an expiration"
+ );
+ }
+
+ try {
+ $expiration = strtotime($tokenData['expiresAt']);
+ } catch (\Exception $e) {
+ throw new TokenException("Cached SSO token returned an invalid expiration");
+ }
+ if ($expiration > time()) {
+ throw new TokenException("Cached SSO token returned an expired token");
+ }
+ return $tokenData;
+ }
+
+ /**
+ * @param array $tokenData
+ * @param string $tokenLocation
+ * @return void
+ */
+ private function writeNewTokenDataToDisk(array $tokenData, $tokenLocation)
+ {
+ $tokenData['expiresAt'] = gmdate(
+ 'Y-m-d\TH:i:s\Z',
+ $tokenData['expiresAt']
+ );
+ file_put_contents($tokenLocation, json_encode(array_filter($tokenData)));
+ }
+}