No Description

CredentialsLoader.php 6.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  1. <?php
  2. /*
  3. * Copyright 2015 Google Inc.
  4. *
  5. * Licensed under the Apache License, Version 2.0 (the "License");
  6. * you may not use this file except in compliance with the License.
  7. * You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. */
  17. namespace Google\Auth;
  18. use Google\Auth\Credentials\ServiceAccountCredentials;
  19. use Google\Auth\Credentials\UserRefreshCredentials;
  20. /**
  21. * CredentialsLoader contains the behaviour used to locate and find default
  22. * credentials files on the file system.
  23. */
  24. abstract class CredentialsLoader implements FetchAuthTokenInterface
  25. {
  26. const TOKEN_CREDENTIAL_URI = 'https://www.googleapis.com/oauth2/v4/token';
  27. const ENV_VAR = 'GOOGLE_APPLICATION_CREDENTIALS';
  28. const WELL_KNOWN_PATH = 'gcloud/application_default_credentials.json';
  29. const NON_WINDOWS_WELL_KNOWN_PATH_BASE = '.config';
  30. const AUTH_METADATA_KEY = 'authorization';
  31. /**
  32. * @param string $cause
  33. * @return string
  34. */
  35. private static function unableToReadEnv($cause)
  36. {
  37. $msg = 'Unable to read the credential file specified by ';
  38. $msg .= ' GOOGLE_APPLICATION_CREDENTIALS: ';
  39. $msg .= $cause;
  40. return $msg;
  41. }
  42. /**
  43. * @return bool
  44. */
  45. private static function isOnWindows()
  46. {
  47. return strtoupper(substr(PHP_OS, 0, 3)) === 'WIN';
  48. }
  49. /**
  50. * Load a JSON key from the path specified in the environment.
  51. *
  52. * Load a JSON key from the path specified in the environment
  53. * variable GOOGLE_APPLICATION_CREDENTIALS. Return null if
  54. * GOOGLE_APPLICATION_CREDENTIALS is not specified.
  55. *
  56. * @return array JSON key | null
  57. */
  58. public static function fromEnv()
  59. {
  60. $path = getenv(self::ENV_VAR);
  61. if (empty($path)) {
  62. return;
  63. }
  64. if (!file_exists($path)) {
  65. $cause = 'file ' . $path . ' does not exist';
  66. throw new \DomainException(self::unableToReadEnv($cause));
  67. }
  68. $jsonKey = file_get_contents($path);
  69. return json_decode($jsonKey, true);
  70. }
  71. /**
  72. * Load a JSON key from a well known path.
  73. *
  74. * The well known path is OS dependent:
  75. * - windows: %APPDATA%/gcloud/application_default_credentials.json
  76. * - others: $HOME/.config/gcloud/application_default_credentials.json
  77. *
  78. * If the file does not exists, this returns null.
  79. *
  80. * @return array JSON key | null
  81. */
  82. public static function fromWellKnownFile()
  83. {
  84. $rootEnv = self::isOnWindows() ? 'APPDATA' : 'HOME';
  85. $path = [getenv($rootEnv)];
  86. if (!self::isOnWindows()) {
  87. $path[] = self::NON_WINDOWS_WELL_KNOWN_PATH_BASE;
  88. }
  89. $path[] = self::WELL_KNOWN_PATH;
  90. $path = implode(DIRECTORY_SEPARATOR, $path);
  91. if (!file_exists($path)) {
  92. return;
  93. }
  94. $jsonKey = file_get_contents($path);
  95. return json_decode($jsonKey, true);
  96. }
  97. /**
  98. * Create a new Credentials instance.
  99. *
  100. * @param string|array $scope the scope of the access request, expressed
  101. * either as an Array or as a space-delimited String.
  102. * @param array $jsonKey the JSON credentials.
  103. *
  104. * @return ServiceAccountCredentials|UserRefreshCredentials
  105. */
  106. public static function makeCredentials($scope, array $jsonKey)
  107. {
  108. if (!array_key_exists('type', $jsonKey)) {
  109. throw new \InvalidArgumentException('json key is missing the type field');
  110. }
  111. if ($jsonKey['type'] == 'service_account') {
  112. return new ServiceAccountCredentials($scope, $jsonKey);
  113. } elseif ($jsonKey['type'] == 'authorized_user') {
  114. return new UserRefreshCredentials($scope, $jsonKey);
  115. } else {
  116. throw new \InvalidArgumentException('invalid value in the type field');
  117. }
  118. }
  119. /**
  120. * Create an authorized HTTP Client from an instance of FetchAuthTokenInterface.
  121. *
  122. * @param FetchAuthTokenInterface $fetcher is used to fetch the auth token
  123. * @param array $httpClientOptoins (optional) Array of request options to apply.
  124. * @param callable $httpHandler (optional) http client to fetch the token.
  125. * @param callable $tokenCallback (optional) function to be called when a new token is fetched.
  126. *
  127. * @return \GuzzleHttp\Client
  128. */
  129. public static function makeHttpClient(
  130. FetchAuthTokenInterface $fetcher,
  131. array $httpClientOptions = [],
  132. callable $httpHandler = null,
  133. callable $tokenCallback = null
  134. ) {
  135. $version = \GuzzleHttp\ClientInterface::VERSION;
  136. switch ($version[0]) {
  137. case '5':
  138. $client = new \GuzzleHttp\Client($httpClientOptions);
  139. $client->setDefaultOption('auth', 'google_auth');
  140. $subscriber = new Subscriber\AuthTokenSubscriber(
  141. $fetcher,
  142. $httpHandler,
  143. $tokenCallback
  144. );
  145. $client->getEmitter()->attach($subscriber);
  146. return $client;
  147. case '6':
  148. $middleware = new Middleware\AuthTokenMiddleware(
  149. $fetcher,
  150. $httpHandler,
  151. $tokenCallback
  152. );
  153. $stack = \GuzzleHttp\HandlerStack::create();
  154. $stack->push($middleware);
  155. return new \GuzzleHttp\Client([
  156. 'handler' => $stack,
  157. 'auth' => 'google_auth',
  158. ] + $httpClientOptions);
  159. default:
  160. throw new \Exception('Version not supported');
  161. }
  162. }
  163. /**
  164. * export a callback function which updates runtime metadata.
  165. *
  166. * @return array updateMetadata function
  167. */
  168. public function getUpdateMetadataFunc()
  169. {
  170. return array($this, 'updateMetadata');
  171. }
  172. /**
  173. * Updates metadata with the authorization token.
  174. *
  175. * @param array $metadata metadata hashmap
  176. * @param string $authUri optional auth uri
  177. * @param callable $httpHandler callback which delivers psr7 request
  178. *
  179. * @return array updated metadata hashmap
  180. */
  181. public function updateMetadata(
  182. $metadata,
  183. $authUri = null,
  184. callable $httpHandler = null
  185. ) {
  186. $result = $this->fetchAuthToken($httpHandler);
  187. if (!isset($result['access_token'])) {
  188. return $metadata;
  189. }
  190. $metadata_copy = $metadata;
  191. $metadata_copy[self::AUTH_METADATA_KEY] = array('Bearer ' . $result['access_token']);
  192. return $metadata_copy;
  193. }
  194. }