| 1 | efrain | 1 | <?php
 | 
        
           |  |  | 2 | namespace Aws\Credentials;
 | 
        
           |  |  | 3 |   | 
        
           |  |  | 4 | use Aws\Exception\CredentialsException;
 | 
        
           |  |  | 5 | use GuzzleHttp\Psr7\Request;
 | 
        
           |  |  | 6 | use GuzzleHttp\Promise\PromiseInterface;
 | 
        
           |  |  | 7 | use Psr\Http\Message\ResponseInterface;
 | 
        
           |  |  | 8 |   | 
        
           |  |  | 9 | /**
 | 
        
           |  |  | 10 |  * Credential provider that fetches credentials with GET request.
 | 
        
           |  |  | 11 |  * ECS environment variable is used in constructing request URI.
 | 
        
           |  |  | 12 |  */
 | 
        
           |  |  | 13 | class EcsCredentialProvider
 | 
        
           |  |  | 14 | {
 | 
        
           |  |  | 15 |     const SERVER_URI = 'http://169.254.170.2';
 | 
        
           |  |  | 16 |     const ENV_URI = "AWS_CONTAINER_CREDENTIALS_RELATIVE_URI";
 | 
        
           |  |  | 17 |     const ENV_FULL_URI = "AWS_CONTAINER_CREDENTIALS_FULL_URI";
 | 
        
           |  |  | 18 |     const ENV_AUTH_TOKEN = "AWS_CONTAINER_AUTHORIZATION_TOKEN";
 | 
        
           |  |  | 19 |     const ENV_TIMEOUT = 'AWS_METADATA_SERVICE_TIMEOUT';
 | 
        
           |  |  | 20 |   | 
        
           |  |  | 21 |     /** @var callable */
 | 
        
           |  |  | 22 |     private $client;
 | 
        
           |  |  | 23 |   | 
        
           |  |  | 24 |     /** @var float|mixed */
 | 
        
           |  |  | 25 |     private $timeout;
 | 
        
           |  |  | 26 |   | 
        
           |  |  | 27 |     /**
 | 
        
           |  |  | 28 |      *  The constructor accepts following options:
 | 
        
           |  |  | 29 |      *  - timeout: (optional) Connection timeout, in seconds, default 1.0
 | 
        
           |  |  | 30 |      *  - client: An EcsClient to make request from
 | 
        
           |  |  | 31 |      *
 | 
        
           |  |  | 32 |      * @param array $config Configuration options
 | 
        
           |  |  | 33 |      */
 | 
        
           |  |  | 34 |     public function __construct(array $config = [])
 | 
        
           |  |  | 35 |     {
 | 
        
           |  |  | 36 |         $timeout = getenv(self::ENV_TIMEOUT);
 | 
        
           |  |  | 37 |   | 
        
           |  |  | 38 |         if (!$timeout) {
 | 
        
           |  |  | 39 |             $timeout = isset($_SERVER[self::ENV_TIMEOUT])
 | 
        
           |  |  | 40 |                 ? $_SERVER[self::ENV_TIMEOUT]
 | 
        
           |  |  | 41 |                 : (isset($config['timeout']) ? $config['timeout'] : 1.0);
 | 
        
           |  |  | 42 |         }
 | 
        
           |  |  | 43 |   | 
        
           |  |  | 44 |         $this->timeout = (float) $timeout;
 | 
        
           |  |  | 45 |         $this->client = isset($config['client'])
 | 
        
           |  |  | 46 |             ? $config['client']
 | 
        
           |  |  | 47 |             : \Aws\default_http_handler();
 | 
        
           |  |  | 48 |     }
 | 
        
           |  |  | 49 |   | 
        
           |  |  | 50 |     /**
 | 
        
           |  |  | 51 |      * Load ECS credentials
 | 
        
           |  |  | 52 |      *
 | 
        
           |  |  | 53 |      * @return PromiseInterface
 | 
        
           |  |  | 54 |      */
 | 
        
           |  |  | 55 |     public function __invoke()
 | 
        
           |  |  | 56 |     {
 | 
        
           |  |  | 57 |         $client = $this->client;
 | 
        
           |  |  | 58 |         $request = new Request('GET', self::getEcsUri());
 | 
        
           |  |  | 59 |   | 
        
           |  |  | 60 |         $headers = $this->setHeaderForAuthToken();
 | 
        
           |  |  | 61 |         return $client(
 | 
        
           |  |  | 62 |             $request,
 | 
        
           |  |  | 63 |             [
 | 
        
           |  |  | 64 |                 'timeout' => $this->timeout,
 | 
        
           |  |  | 65 |                 'proxy' => '',
 | 
        
           |  |  | 66 |                 'headers' => $headers
 | 
        
           |  |  | 67 |             ]
 | 
        
           |  |  | 68 |         )->then(function (ResponseInterface $response) {
 | 
        
           |  |  | 69 |             $result = $this->decodeResult((string) $response->getBody());
 | 
        
           |  |  | 70 |             return new Credentials(
 | 
        
           |  |  | 71 |                 $result['AccessKeyId'],
 | 
        
           |  |  | 72 |                 $result['SecretAccessKey'],
 | 
        
           |  |  | 73 |                 $result['Token'],
 | 
        
           |  |  | 74 |                 strtotime($result['Expiration'])
 | 
        
           |  |  | 75 |             );
 | 
        
           |  |  | 76 |         })->otherwise(function ($reason) {
 | 
        
           |  |  | 77 |             $reason = is_array($reason) ? $reason['exception'] : $reason;
 | 
        
           |  |  | 78 |             $msg = $reason->getMessage();
 | 
        
           |  |  | 79 |             throw new CredentialsException(
 | 
        
           |  |  | 80 |                 "Error retrieving credential from ECS ($msg)"
 | 
        
           |  |  | 81 |             );
 | 
        
           |  |  | 82 |         });
 | 
        
           |  |  | 83 |     }
 | 
        
           |  |  | 84 |   | 
        
           |  |  | 85 |     private function getEcsAuthToken()
 | 
        
           |  |  | 86 |     {
 | 
        
           |  |  | 87 |         return getenv(self::ENV_AUTH_TOKEN);
 | 
        
           |  |  | 88 |     }
 | 
        
           |  |  | 89 |   | 
        
           |  |  | 90 |     public function setHeaderForAuthToken(){
 | 
        
           |  |  | 91 |         $authToken = self::getEcsAuthToken();
 | 
        
           |  |  | 92 |         $headers = [];
 | 
        
           |  |  | 93 |         if(!empty($authToken))
 | 
        
           |  |  | 94 |             $headers = ['Authorization' => $authToken];
 | 
        
           |  |  | 95 |   | 
        
           |  |  | 96 |         return $headers;
 | 
        
           |  |  | 97 |     }
 | 
        
           |  |  | 98 |   | 
        
           |  |  | 99 |     /**
 | 
        
           |  |  | 100 |      * Fetch credential URI from ECS environment variable
 | 
        
           |  |  | 101 |      *
 | 
        
           |  |  | 102 |      * @return string Returns ECS URI
 | 
        
           |  |  | 103 |      */
 | 
        
           |  |  | 104 |     private function getEcsUri()
 | 
        
           |  |  | 105 |     {
 | 
        
           |  |  | 106 |         $credsUri = getenv(self::ENV_URI);
 | 
        
           |  |  | 107 |   | 
        
           |  |  | 108 |         if ($credsUri === false) {
 | 
        
           |  |  | 109 |             $credsUri = isset($_SERVER[self::ENV_URI]) ? $_SERVER[self::ENV_URI] : '';
 | 
        
           |  |  | 110 |         }
 | 
        
           |  |  | 111 |   | 
        
           |  |  | 112 |         if(empty($credsUri)){
 | 
        
           |  |  | 113 |             $credFullUri = getenv(self::ENV_FULL_URI);
 | 
        
           |  |  | 114 |             if($credFullUri === false){
 | 
        
           |  |  | 115 |                 $credFullUri = isset($_SERVER[self::ENV_FULL_URI]) ? $_SERVER[self::ENV_FULL_URI] : '';
 | 
        
           |  |  | 116 |             }
 | 
        
           |  |  | 117 |   | 
        
           |  |  | 118 |             if(!empty($credFullUri))
 | 
        
           |  |  | 119 |                 return $credFullUri;
 | 
        
           |  |  | 120 |         }
 | 
        
           |  |  | 121 |   | 
        
           |  |  | 122 |         return self::SERVER_URI . $credsUri;
 | 
        
           |  |  | 123 |     }
 | 
        
           |  |  | 124 |   | 
        
           |  |  | 125 |     private function decodeResult($response)
 | 
        
           |  |  | 126 |     {
 | 
        
           |  |  | 127 |         $result = json_decode($response, true);
 | 
        
           |  |  | 128 |   | 
        
           |  |  | 129 |         if (!isset($result['AccessKeyId'])) {
 | 
        
           |  |  | 130 |             throw new CredentialsException('Unexpected ECS credential value');
 | 
        
           |  |  | 131 |         }
 | 
        
           |  |  | 132 |         return $result;
 | 
        
           |  |  | 133 |     }
 | 
        
           |  |  | 134 | }
 |