| 1 |
<?php |
| 2 |
/* |
| 3 |
* Copyright 2010 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 |
|
| 18 |
namespace Google; |
| 19 |
|
| 20 |
use BadMethodCallException; |
| 21 |
use DomainException; |
| 22 |
use Google\AccessToken\Revoke; |
| 23 |
use Google\AccessToken\Verify; |
| 24 |
use Google\Auth\ApplicationDefaultCredentials; |
| 25 |
use Google\Auth\Cache\MemoryCacheItemPool; |
| 26 |
use Google\Auth\Credentials\ServiceAccountCredentials; |
| 27 |
use Google\Auth\Credentials\UserRefreshCredentials; |
| 28 |
use Google\Auth\CredentialsLoader; |
| 29 |
use Google\Auth\FetchAuthTokenCache; |
| 30 |
use Google\Auth\HttpHandler\HttpHandlerFactory; |
| 31 |
use Google\Auth\OAuth2; |
| 32 |
use Google\AuthHandler\AuthHandlerFactory; |
| 33 |
use Google\Http\REST; |
| 34 |
use GuzzleHttp\Client as GuzzleClient; |
| 35 |
use GuzzleHttp\ClientInterface; |
| 36 |
use GuzzleHttp\Ring\Client\StreamHandler; |
| 37 |
use InvalidArgumentException; |
| 38 |
use LogicException; |
| 39 |
use Monolog\Handler\StreamHandler as MonologStreamHandler; |
| 40 |
use Monolog\Handler\SyslogHandler as MonologSyslogHandler; |
| 41 |
use Monolog\Logger; |
| 42 |
use Psr\Cache\CacheItemPoolInterface; |
| 43 |
use Psr\Http\Message\RequestInterface; |
| 44 |
use Psr\Http\Message\ResponseInterface; |
| 45 |
use Psr\Log\LoggerInterface; |
| 46 |
use UnexpectedValueException; |
| 47 |
|
| 48 |
/** |
| 49 |
* The Google API Client |
| 50 |
* https://github.com/google/google-api-php-client |
| 51 |
*/ |
| 52 |
class Client |
| 53 |
{ |
| 54 |
const LIBVER = "2.12.6"; |
| 55 |
const USER_AGENT_SUFFIX = "google-api-php-client/"; |
| 56 |
const OAUTH2_REVOKE_URI = 'https://oauth2.googleapis.com/revoke'; |
| 57 |
const OAUTH2_TOKEN_URI = 'https://oauth2.googleapis.com/token'; |
| 58 |
const OAUTH2_AUTH_URL = 'https://accounts.google.com/o/oauth2/auth'; |
| 59 |
const API_BASE_PATH = 'https://www.googleapis.com'; |
| 60 |
|
| 61 |
/** |
| 62 |
* @var ?OAuth2 $auth |
| 63 |
*/ |
| 64 |
private $auth; |
| 65 |
|
| 66 |
/** |
| 67 |
* @var ClientInterface $http |
| 68 |
*/ |
| 69 |
private $http; |
| 70 |
|
| 71 |
/** |
| 72 |
* @var ?CacheItemPoolInterface $cache |
| 73 |
*/ |
| 74 |
private $cache; |
| 75 |
|
| 76 |
/** |
| 77 |
* @var array access token |
| 78 |
*/ |
| 79 |
private $token; |
| 80 |
|
| 81 |
/** |
| 82 |
* @var array $config |
| 83 |
*/ |
| 84 |
private $config; |
| 85 |
|
| 86 |
/** |
| 87 |
* @var ?LoggerInterface $logger |
| 88 |
*/ |
| 89 |
private $logger; |
| 90 |
|
| 91 |
/** |
| 92 |
* @var ?CredentialsLoader $credentials |
| 93 |
*/ |
| 94 |
private $credentials; |
| 95 |
|
| 96 |
/** |
| 97 |
* @var boolean $deferExecution |
| 98 |
*/ |
| 99 |
private $deferExecution = false; |
| 100 |
|
| 101 |
/** @var array $scopes */ |
| 102 |
// Scopes requested by the client |
| 103 |
protected $requestedScopes = []; |
| 104 |
|
| 105 |
/** |
| 106 |
* Construct the Google Client. |
| 107 |
* |
| 108 |
* @param array $config |
| 109 |
*/ |
| 110 |
public function __construct(array $config = []) |
| 111 |
{ |
| 112 |
$this->config = array_merge([ |
| 113 |
'application_name' => '', |
| 114 |
|
| 115 |
// Don't change these unless you're working against a special development |
| 116 |
// or testing environment. |
| 117 |
'base_path' => self::API_BASE_PATH, |
| 118 |
|
| 119 |
// https://developers.google.com/console |
| 120 |
'client_id' => '', |
| 121 |
'client_secret' => '', |
| 122 |
|
| 123 |
// Can be a path to JSON credentials or an array representing those |
| 124 |
// credentials (@see Google\Client::setAuthConfig), or an instance of |
| 125 |
// Google\Auth\CredentialsLoader. |
| 126 |
'credentials' => null, |
| 127 |
// @see Google\Client::setScopes |
| 128 |
'scopes' => null, |
| 129 |
// Sets X-Goog-User-Project, which specifies a user project to bill |
| 130 |
// for access charges associated with the request |
| 131 |
'quota_project' => null, |
| 132 |
|
| 133 |
'redirect_uri' => null, |
| 134 |
'state' => null, |
| 135 |
|
| 136 |
// Simple API access key, also from the API console. Ensure you get |
| 137 |
// a Server key, and not a Browser key. |
| 138 |
'developer_key' => '', |
| 139 |
|
| 140 |
// For use with Google Cloud Platform |
| 141 |
// fetch the ApplicationDefaultCredentials, if applicable |
| 142 |
// @see https://developers.google.com/identity/protocols/application-default-credentials |
| 143 |
'use_application_default_credentials' => false, |
| 144 |
'signing_key' => null, |
| 145 |
'signing_algorithm' => null, |
| 146 |
'subject' => null, |
| 147 |
|
| 148 |
// Other OAuth2 parameters. |
| 149 |
'hd' => '', |
| 150 |
'prompt' => '', |
| 151 |
'openid.realm' => '', |
| 152 |
'include_granted_scopes' => null, |
| 153 |
'login_hint' => '', |
| 154 |
'request_visible_actions' => '', |
| 155 |
'access_type' => 'online', |
| 156 |
'approval_prompt' => 'auto', |
| 157 |
|
| 158 |
// Task Runner retry configuration |
| 159 |
// @see Google\Task\Runner |
| 160 |
'retry' => [], |
| 161 |
'retry_map' => null, |
| 162 |
|
| 163 |
// Cache class implementing Psr\Cache\CacheItemPoolInterface. |
| 164 |
// Defaults to Google\Auth\Cache\MemoryCacheItemPool. |
| 165 |
'cache' => null, |
| 166 |
// cache config for downstream auth caching |
| 167 |
'cache_config' => [], |
| 168 |
|
| 169 |
// function to be called when an access token is fetched |
| 170 |
// follows the signature function ($cacheKey, $accessToken) |
| 171 |
'token_callback' => null, |
| 172 |
|
| 173 |
// Service class used in Google\Client::verifyIdToken. |
| 174 |
// Explicitly pass this in to avoid setting JWT::$leeway |
| 175 |
'jwt' => null, |
| 176 |
|
| 177 |
// Setting api_format_v2 will return more detailed error messages |
| 178 |
// from certain APIs. |
| 179 |
'api_format_v2' => false |
| 180 |
], $config); |
| 181 |
|
| 182 |
if (!is_null($this->config['credentials'])) { |
| 183 |
if ($this->config['credentials'] instanceof CredentialsLoader) { |
| 184 |
$this->credentials = $this->config['credentials']; |
| 185 |
} else { |
| 186 |
$this->setAuthConfig($this->config['credentials']); |
| 187 |
} |
| 188 |
unset($this->config['credentials']); |
| 189 |
} |
| 190 |
|
| 191 |
if (!is_null($this->config['scopes'])) { |
| 192 |
$this->setScopes($this->config['scopes']); |
| 193 |
unset($this->config['scopes']); |
| 194 |
} |
| 195 |
|
| 196 |
// Set a default token callback to update the in-memory access token |
| 197 |
if (is_null($this->config['token_callback'])) { |
| 198 |
$this->config['token_callback'] = function ($cacheKey, $newAccessToken) { |
| 199 |
$this->setAccessToken( |
| 200 |
[ |
| 201 |
'access_token' => $newAccessToken, |
| 202 |
'expires_in' => 3600, // Google default |
| 203 |
'created' => time(), |
| 204 |
] |
| 205 |
); |
| 206 |
}; |
| 207 |
} |
| 208 |
|
| 209 |
if (!is_null($this->config['cache'])) { |
| 210 |
$this->setCache($this->config['cache']); |
| 211 |
unset($this->config['cache']); |
| 212 |
} |
| 213 |
} |
| 214 |
|
| 215 |
/** |
| 216 |
* Get a string containing the version of the library. |
| 217 |
* |
| 218 |
* @return string |
| 219 |
*/ |
| 220 |
public function getLibraryVersion() |
| 221 |
{ |
| 222 |
return self::LIBVER; |
| 223 |
} |
| 224 |
|
| 225 |
/** |
| 226 |
* For backwards compatibility |
| 227 |
* alias for fetchAccessTokenWithAuthCode |
| 228 |
* |
| 229 |
* @param string $code string code from accounts.google.com |
| 230 |
* @return array access token |
| 231 |
* @deprecated |
| 232 |
*/ |
| 233 |
public function authenticate($code) |
| 234 |
{ |
| 235 |
return $this->fetchAccessTokenWithAuthCode($code); |
| 236 |
} |
| 237 |
|
| 238 |
/** |
| 239 |
* Attempt to exchange a code for an valid authentication token. |
| 240 |
* Helper wrapped around the OAuth 2.0 implementation. |
| 241 |
* |
| 242 |
* @param string $code code from accounts.google.com |
| 243 |
* @return array access token |
| 244 |
*/ |
| 245 |
public function fetchAccessTokenWithAuthCode($code) |
| 246 |
{ |
| 247 |
if (strlen($code) == 0) { |
| 248 |
throw new InvalidArgumentException("Invalid code"); |
| 249 |
} |
| 250 |
|
| 251 |
$auth = $this->getOAuth2Service(); |
| 252 |
$auth->setCode($code); |
| 253 |
$auth->setRedirectUri($this->getRedirectUri()); |
| 254 |
|
| 255 |
$httpHandler = HttpHandlerFactory::build($this->getHttpClient()); |
| 256 |
$creds = $auth->fetchAuthToken($httpHandler); |
| 257 |
if ($creds && isset($creds['access_token'])) { |
| 258 |
$creds['created'] = time(); |
| 259 |
$this->setAccessToken($creds); |
| 260 |
} |
| 261 |
|
| 262 |
return $creds; |
| 263 |
} |
| 264 |
|
| 265 |
/** |
| 266 |
* For backwards compatibility |
| 267 |
* alias for fetchAccessTokenWithAssertion |
| 268 |
* |
| 269 |
* @return array access token |
| 270 |
* @deprecated |
| 271 |
*/ |
| 272 |
public function refreshTokenWithAssertion() |
| 273 |
{ |
| 274 |
return $this->fetchAccessTokenWithAssertion(); |
| 275 |
} |
| 276 |
|
| 277 |
/** |
| 278 |
* Fetches a fresh access token with a given assertion token. |
| 279 |
* @param ClientInterface $authHttp optional. |
| 280 |
* @return array access token |
| 281 |
*/ |
| 282 |
public function fetchAccessTokenWithAssertion(ClientInterface $authHttp = null) |
| 283 |
{ |
| 284 |
if (!$this->isUsingApplicationDefaultCredentials()) { |
| 285 |
throw new DomainException( |
| 286 |
'set the JSON service account credentials using' |
| 287 |
. ' Google\Client::setAuthConfig or set the path to your JSON file' |
| 288 |
. ' with the "GOOGLE_APPLICATION_CREDENTIALS" environment variable' |
| 289 |
. ' and call Google\Client::useApplicationDefaultCredentials to' |
| 290 |
. ' refresh a token with assertion.' |
| 291 |
); |
| 292 |
} |
| 293 |
|
| 294 |
$this->getLogger()->log( |
| 295 |
'info', |
| 296 |
'OAuth2 access token refresh with Signed JWT assertion grants.' |
| 297 |
); |
| 298 |
|
| 299 |
$credentials = $this->createApplicationDefaultCredentials(); |
| 300 |
|
| 301 |
$httpHandler = HttpHandlerFactory::build($authHttp); |
| 302 |
$creds = $credentials->fetchAuthToken($httpHandler); |
| 303 |
if ($creds && isset($creds['access_token'])) { |
| 304 |
$creds['created'] = time(); |
| 305 |
$this->setAccessToken($creds); |
| 306 |
} |
| 307 |
|
| 308 |
return $creds; |
| 309 |
} |
| 310 |
|
| 311 |
/** |
| 312 |
* For backwards compatibility |
| 313 |
* alias for fetchAccessTokenWithRefreshToken |
| 314 |
* |
| 315 |
* @param string $refreshToken |
| 316 |
* @return array access token |
| 317 |
*/ |
| 318 |
public function refreshToken($refreshToken) |
| 319 |
{ |
| 320 |
return $this->fetchAccessTokenWithRefreshToken($refreshToken); |
| 321 |
} |
| 322 |
|
| 323 |
/** |
| 324 |
* Fetches a fresh OAuth 2.0 access token with the given refresh token. |
| 325 |
* @param string $refreshToken |
| 326 |
* @return array access token |
| 327 |
*/ |
| 328 |
public function fetchAccessTokenWithRefreshToken($refreshToken = null) |
| 329 |
{ |
| 330 |
if (null === $refreshToken) { |
| 331 |
if (!isset($this->token['refresh_token'])) { |
| 332 |
throw new LogicException( |
| 333 |
'refresh token must be passed in or set as part of setAccessToken' |
| 334 |
); |
| 335 |
} |
| 336 |
$refreshToken = $this->token['refresh_token']; |
| 337 |
} |
| 338 |
$this->getLogger()->info('OAuth2 access token refresh'); |
| 339 |
$auth = $this->getOAuth2Service(); |
| 340 |
$auth->setRefreshToken($refreshToken); |
| 341 |
|
| 342 |
$httpHandler = HttpHandlerFactory::build($this->getHttpClient()); |
| 343 |
$creds = $auth->fetchAuthToken($httpHandler); |
| 344 |
if ($creds && isset($creds['access_token'])) { |
| 345 |
$creds['created'] = time(); |
| 346 |
if (!isset($creds['refresh_token'])) { |
| 347 |
$creds['refresh_token'] = $refreshToken; |
| 348 |
} |
| 349 |
$this->setAccessToken($creds); |
| 350 |
} |
| 351 |
|
| 352 |
return $creds; |
| 353 |
} |
| 354 |
|
| 355 |
/** |
| 356 |
* Create a URL to obtain user authorization. |
| 357 |
* The authorization endpoint allows the user to first |
| 358 |
* authenticate, and then grant/deny the access request. |
| 359 |
* @param string|array $scope The scope is expressed as an array or list of space-delimited strings. |
| 360 |
* @return string |
| 361 |
*/ |
| 362 |
public function createAuthUrl($scope = null) |
| 363 |
{ |
| 364 |
if (empty($scope)) { |
| 365 |
$scope = $this->prepareScopes(); |
| 366 |
} |
| 367 |
if (is_array($scope)) { |
| 368 |
$scope = implode(' ', $scope); |
| 369 |
} |
| 370 |
|
| 371 |
// only accept one of prompt or approval_prompt |
| 372 |
$approvalPrompt = $this->config['prompt'] |
| 373 |
? null |
| 374 |
: $this->config['approval_prompt']; |
| 375 |
|
| 376 |
// include_granted_scopes should be string "true", string "false", or null |
| 377 |
$includeGrantedScopes = $this->config['include_granted_scopes'] === null |
| 378 |
? null |
| 379 |
: var_export($this->config['include_granted_scopes'], true); |
| 380 |
|
| 381 |
$params = array_filter([ |
| 382 |
'access_type' => $this->config['access_type'], |
| 383 |
'approval_prompt' => $approvalPrompt, |
| 384 |
'hd' => $this->config['hd'], |
| 385 |
'include_granted_scopes' => $includeGrantedScopes, |
| 386 |
'login_hint' => $this->config['login_hint'], |
| 387 |
'openid.realm' => $this->config['openid.realm'], |
| 388 |
'prompt' => $this->config['prompt'], |
| 389 |
'response_type' => 'code', |
| 390 |
'scope' => $scope, |
| 391 |
'state' => $this->config['state'], |
| 392 |
]); |
| 393 |
|
| 394 |
// If the list of scopes contains plus.login, add request_visible_actions |
| 395 |
// to auth URL. |
| 396 |
$rva = $this->config['request_visible_actions']; |
| 397 |
if (strlen($rva) > 0 && false !== strpos($scope, 'plus.login')) { |
| 398 |
$params['request_visible_actions'] = $rva; |
| 399 |
} |
| 400 |
|
| 401 |
$auth = $this->getOAuth2Service(); |
| 402 |
|
| 403 |
return (string) $auth->buildFullAuthorizationUri($params); |
| 404 |
} |
| 405 |
|
| 406 |
/** |
| 407 |
* Adds auth listeners to the HTTP client based on the credentials |
| 408 |
* set in the Google API Client object |
| 409 |
* |
| 410 |
* @param ClientInterface $http the http client object. |
| 411 |
* @return ClientInterface the http client object |
| 412 |
*/ |
| 413 |
public function authorize(ClientInterface $http = null) |
| 414 |
{ |
| 415 |
$http = $http ?: $this->getHttpClient(); |
| 416 |
$authHandler = $this->getAuthHandler(); |
| 417 |
|
| 418 |
// These conditionals represent the decision tree for authentication |
| 419 |
// 1. Check if a Google\Auth\CredentialsLoader instance has been supplied via the "credentials" option |
| 420 |
// 2. Check for Application Default Credentials |
| 421 |
// 3a. Check for an Access Token |
| 422 |
// 3b. If access token exists but is expired, try to refresh it |
| 423 |
// 4. Check for API Key |
| 424 |
if ($this->credentials) { |
| 425 |
return $authHandler->attachCredentials( |
| 426 |
$http, |
| 427 |
$this->credentials, |
| 428 |
$this->config['token_callback'] |
| 429 |
); |
| 430 |
} |
| 431 |
|
| 432 |
if ($this->isUsingApplicationDefaultCredentials()) { |
| 433 |
$credentials = $this->createApplicationDefaultCredentials(); |
| 434 |
return $authHandler->attachCredentialsCache( |
| 435 |
$http, |
| 436 |
$credentials, |
| 437 |
$this->config['token_callback'] |
| 438 |
); |
| 439 |
} |
| 440 |
|
| 441 |
if ($token = $this->getAccessToken()) { |
| 442 |
$scopes = $this->prepareScopes(); |
| 443 |
// add refresh subscriber to request a new token |
| 444 |
if (isset($token['refresh_token']) && $this->isAccessTokenExpired()) { |
| 445 |
$credentials = $this->createUserRefreshCredentials( |
| 446 |
$scopes, |
| 447 |
$token['refresh_token'] |
| 448 |
); |
| 449 |
return $authHandler->attachCredentials( |
| 450 |
$http, |
| 451 |
$credentials, |
| 452 |
$this->config['token_callback'] |
| 453 |
); |
| 454 |
} |
| 455 |
|
| 456 |
return $authHandler->attachToken($http, $token, (array) $scopes); |
| 457 |
} |
| 458 |
|
| 459 |
if ($key = $this->config['developer_key']) { |
| 460 |
return $authHandler->attachKey($http, $key); |
| 461 |
} |
| 462 |
|
| 463 |
return $http; |
| 464 |
} |
| 465 |
|
| 466 |
/** |
| 467 |
* Set the configuration to use application default credentials for |
| 468 |
* authentication |
| 469 |
* |
| 470 |
* @see https://developers.google.com/identity/protocols/application-default-credentials |
| 471 |
* @param boolean $useAppCreds |
| 472 |
*/ |
| 473 |
public function useApplicationDefaultCredentials($useAppCreds = true) |
| 474 |
{ |
| 475 |
$this->config['use_application_default_credentials'] = $useAppCreds; |
| 476 |
} |
| 477 |
|
| 478 |
/** |
| 479 |
* To prevent useApplicationDefaultCredentials from inappropriately being |
| 480 |
* called in a conditional |
| 481 |
* |
| 482 |
* @see https://developers.google.com/identity/protocols/application-default-credentials |
| 483 |
*/ |
| 484 |
public function isUsingApplicationDefaultCredentials() |
| 485 |
{ |
| 486 |
return $this->config['use_application_default_credentials']; |
| 487 |
} |
| 488 |
|
| 489 |
/** |
| 490 |
* Set the access token used for requests. |
| 491 |
* |
| 492 |
* Note that at the time requests are sent, tokens are cached. A token will be |
| 493 |
* cached for each combination of service and authentication scopes. If a |
| 494 |
* cache pool is not provided, creating a new instance of the client will |
| 495 |
* allow modification of access tokens. If a persistent cache pool is |
| 496 |
* provided, in order to change the access token, you must clear the cached |
| 497 |
* token by calling `$client->getCache()->clear()`. (Use caution in this case, |
| 498 |
* as calling `clear()` will remove all cache items, including any items not |
| 499 |
* related to Google API PHP Client.) |
| 500 |
* |
| 501 |
* @param string|array $token |
| 502 |
* @throws InvalidArgumentException |
| 503 |
*/ |
| 504 |
public function setAccessToken($token) |
| 505 |
{ |
| 506 |
if (is_string($token)) { |
| 507 |
if ($json = json_decode($token, true)) { |
| 508 |
$token = $json; |
| 509 |
} else { |
| 510 |
// assume $token is just the token string |
| 511 |
$token = [ |
| 512 |
'access_token' => $token, |
| 513 |
]; |
| 514 |
} |
| 515 |
} |
| 516 |
if ($token == null) { |
| 517 |
throw new InvalidArgumentException('invalid json token'); |
| 518 |
} |
| 519 |
if (!isset($token['access_token'])) { |
| 520 |
throw new InvalidArgumentException("Invalid token format"); |
| 521 |
} |
| 522 |
$this->token = $token; |
| 523 |
} |
| 524 |
|
| 525 |
public function getAccessToken() |
| 526 |
{ |
| 527 |
return $this->token; |
| 528 |
} |
| 529 |
|
| 530 |
/** |
| 531 |
* @return string|null |
| 532 |
*/ |
| 533 |
public function getRefreshToken() |
| 534 |
{ |
| 535 |
if (isset($this->token['refresh_token'])) { |
| 536 |
return $this->token['refresh_token']; |
| 537 |
} |
| 538 |
|
| 539 |
return null; |
| 540 |
} |
| 541 |
|
| 542 |
/** |
| 543 |
* Returns if the access_token is expired. |
| 544 |
* @return bool Returns True if the access_token is expired. |
| 545 |
*/ |
| 546 |
public function isAccessTokenExpired() |
| 547 |
{ |
| 548 |
if (!$this->token) { |
| 549 |
return true; |
| 550 |
} |
| 551 |
|
| 552 |
$created = 0; |
| 553 |
if (isset($this->token['created'])) { |
| 554 |
$created = $this->token['created']; |
| 555 |
} elseif (isset($this->token['id_token'])) { |
| 556 |
// check the ID token for "iat" |
| 557 |
// signature verification is not required here, as we are just |
| 558 |
// using this for convenience to save a round trip request |
| 559 |
// to the Google API server |
| 560 |
$idToken = $this->token['id_token']; |
| 561 |
if (substr_count($idToken, '.') == 2) { |
| 562 |
$parts = explode('.', $idToken); |
| 563 |
$payload = json_decode(base64_decode($parts[1]), true); |
| 564 |
if ($payload && isset($payload['iat'])) { |
| 565 |
$created = $payload['iat']; |
| 566 |
} |
| 567 |
} |
| 568 |
} |
| 569 |
if (!isset($this->token['expires_in'])) { |
| 570 |
// if the token does not have an "expires_in", then it's considered expired |
| 571 |
return true; |
| 572 |
} |
| 573 |
|
| 574 |
// If the token is set to expire in the next 30 seconds. |
| 575 |
return ($created + ($this->token['expires_in'] - 30)) < time(); |
| 576 |
} |
| 577 |
|
| 578 |
/** |
| 579 |
* @deprecated See UPGRADING.md for more information |
| 580 |
*/ |
| 581 |
public function getAuth() |
| 582 |
{ |
| 583 |
throw new BadMethodCallException( |
| 584 |
'This function no longer exists. See UPGRADING.md for more information' |
| 585 |
); |
| 586 |
} |
| 587 |
|
| 588 |
/** |
| 589 |
* @deprecated See UPGRADING.md for more information |
| 590 |
*/ |
| 591 |
public function setAuth($auth) |
| 592 |
{ |
| 593 |
throw new BadMethodCallException( |
| 594 |
'This function no longer exists. See UPGRADING.md for more information' |
| 595 |
); |
| 596 |
} |
| 597 |
|
| 598 |
/** |
| 599 |
* Set the OAuth 2.0 Client ID. |
| 600 |
* @param string $clientId |
| 601 |
*/ |
| 602 |
public function setClientId($clientId) |
| 603 |
{ |
| 604 |
$this->config['client_id'] = $clientId; |
| 605 |
} |
| 606 |
|
| 607 |
public function getClientId() |
| 608 |
{ |
| 609 |
return $this->config['client_id']; |
| 610 |
} |
| 611 |
|
| 612 |
/** |
| 613 |
* Set the OAuth 2.0 Client Secret. |
| 614 |
* @param string $clientSecret |
| 615 |
*/ |
| 616 |
public function setClientSecret($clientSecret) |
| 617 |
{ |
| 618 |
$this->config['client_secret'] = $clientSecret; |
| 619 |
} |
| 620 |
|
| 621 |
public function getClientSecret() |
| 622 |
{ |
| 623 |
return $this->config['client_secret']; |
| 624 |
} |
| 625 |
|
| 626 |
/** |
| 627 |
* Set the OAuth 2.0 Redirect URI. |
| 628 |
* @param string $redirectUri |
| 629 |
*/ |
| 630 |
public function setRedirectUri($redirectUri) |
| 631 |
{ |
| 632 |
$this->config['redirect_uri'] = $redirectUri; |
| 633 |
} |
| 634 |
|
| 635 |
public function getRedirectUri() |
| 636 |
{ |
| 637 |
return $this->config['redirect_uri']; |
| 638 |
} |
| 639 |
|
| 640 |
/** |
| 641 |
* Set OAuth 2.0 "state" parameter to achieve per-request customization. |
| 642 |
* @see http://tools.ietf.org/html/draft-ietf-oauth-v2-22#section-3.1.2.2 |
| 643 |
* @param string $state |
| 644 |
*/ |
| 645 |
public function setState($state) |
| 646 |
{ |
| 647 |
$this->config['state'] = $state; |
| 648 |
} |
| 649 |
|
| 650 |
/** |
| 651 |
* @param string $accessType Possible values for access_type include: |
| 652 |
* {@code "offline"} to request offline access from the user. |
| 653 |
* {@code "online"} to request online access from the user. |
| 654 |
*/ |
| 655 |
public function setAccessType($accessType) |
| 656 |
{ |
| 657 |
$this->config['access_type'] = $accessType; |
| 658 |
} |
| 659 |
|
| 660 |
/** |
| 661 |
* @param string $approvalPrompt Possible values for approval_prompt include: |
| 662 |
* {@code "force"} to force the approval UI to appear. |
| 663 |
* {@code "auto"} to request auto-approval when possible. (This is the default value) |
| 664 |
*/ |
| 665 |
public function setApprovalPrompt($approvalPrompt) |
| 666 |
{ |
| 667 |
$this->config['approval_prompt'] = $approvalPrompt; |
| 668 |
} |
| 669 |
|
| 670 |
/** |
| 671 |
* Set the login hint, email address or sub id. |
| 672 |
* @param string $loginHint |
| 673 |
*/ |
| 674 |
public function setLoginHint($loginHint) |
| 675 |
{ |
| 676 |
$this->config['login_hint'] = $loginHint; |
| 677 |
} |
| 678 |
|
| 679 |
/** |
| 680 |
* Set the application name, this is included in the User-Agent HTTP header. |
| 681 |
* @param string $applicationName |
| 682 |
*/ |
| 683 |
public function setApplicationName($applicationName) |
| 684 |
{ |
| 685 |
$this->config['application_name'] = $applicationName; |
| 686 |
} |
| 687 |
|
| 688 |
/** |
| 689 |
* If 'plus.login' is included in the list of requested scopes, you can use |
| 690 |
* this method to define types of app activities that your app will write. |
| 691 |
* You can find a list of available types here: |
| 692 |
* @link https://developers.google.com/+/api/moment-types |
| 693 |
* |
| 694 |
* @param array $requestVisibleActions Array of app activity types |
| 695 |
*/ |
| 696 |
public function setRequestVisibleActions($requestVisibleActions) |
| 697 |
{ |
| 698 |
if (is_array($requestVisibleActions)) { |
| 699 |
$requestVisibleActions = implode(" ", $requestVisibleActions); |
| 700 |
} |
| 701 |
$this->config['request_visible_actions'] = $requestVisibleActions; |
| 702 |
} |
| 703 |
|
| 704 |
/** |
| 705 |
* Set the developer key to use, these are obtained through the API Console. |
| 706 |
* @see http://code.google.com/apis/console-help/#generatingdevkeys |
| 707 |
* @param string $developerKey |
| 708 |
*/ |
| 709 |
public function setDeveloperKey($developerKey) |
| 710 |
{ |
| 711 |
$this->config['developer_key'] = $developerKey; |
| 712 |
} |
| 713 |
|
| 714 |
/** |
| 715 |
* Set the hd (hosted domain) parameter streamlines the login process for |
| 716 |
* Google Apps hosted accounts. By including the domain of the user, you |
| 717 |
* restrict sign-in to accounts at that domain. |
| 718 |
* @param string $hd the domain to use. |
| 719 |
*/ |
| 720 |
public function setHostedDomain($hd) |
| 721 |
{ |
| 722 |
$this->config['hd'] = $hd; |
| 723 |
} |
| 724 |
|
| 725 |
/** |
| 726 |
* Set the prompt hint. Valid values are none, consent and select_account. |
| 727 |
* If no value is specified and the user has not previously authorized |
| 728 |
* access, then the user is shown a consent screen. |
| 729 |
* @param string $prompt |
| 730 |
* {@code "none"} Do not display any authentication or consent screens. Must not be specified with other values. |
| 731 |
* {@code "consent"} Prompt the user for consent. |
| 732 |
* {@code "select_account"} Prompt the user to select an account. |
| 733 |
*/ |
| 734 |
public function setPrompt($prompt) |
| 735 |
{ |
| 736 |
$this->config['prompt'] = $prompt; |
| 737 |
} |
| 738 |
|
| 739 |
/** |
| 740 |
* openid.realm is a parameter from the OpenID 2.0 protocol, not from OAuth |
| 741 |
* 2.0. It is used in OpenID 2.0 requests to signify the URL-space for which |
| 742 |
* an authentication request is valid. |
| 743 |
* @param string $realm the URL-space to use. |
| 744 |
*/ |
| 745 |
public function setOpenidRealm($realm) |
| 746 |
{ |
| 747 |
$this->config['openid.realm'] = $realm; |
| 748 |
} |
| 749 |
|
| 750 |
/** |
| 751 |
* If this is provided with the value true, and the authorization request is |
| 752 |
* granted, the authorization will include any previous authorizations |
| 753 |
* granted to this user/application combination for other scopes. |
| 754 |
* @param bool $include the URL-space to use. |
| 755 |
*/ |
| 756 |
public function setIncludeGrantedScopes($include) |
| 757 |
{ |
| 758 |
$this->config['include_granted_scopes'] = $include; |
| 759 |
} |
| 760 |
|
| 761 |
/** |
| 762 |
* sets function to be called when an access token is fetched |
| 763 |
* @param callable $tokenCallback - function ($cacheKey, $accessToken) |
| 764 |
*/ |
| 765 |
public function setTokenCallback(callable $tokenCallback) |
| 766 |
{ |
| 767 |
$this->config['token_callback'] = $tokenCallback; |
| 768 |
} |
| 769 |
|
| 770 |
/** |
| 771 |
* Revoke an OAuth2 access token or refresh token. This method will revoke the current access |
| 772 |
* token, if a token isn't provided. |
| 773 |
* |
| 774 |
* @param string|array|null $token The token (access token or a refresh token) that should be revoked. |
| 775 |
* @return boolean Returns True if the revocation was successful, otherwise False. |
| 776 |
*/ |
| 777 |
public function revokeToken($token = null) |
| 778 |
{ |
| 779 |
$tokenRevoker = new Revoke($this->getHttpClient()); |
| 780 |
|
| 781 |
return $tokenRevoker->revokeToken($token ?: $this->getAccessToken()); |
| 782 |
} |
| 783 |
|
| 784 |
/** |
| 785 |
* Verify an id_token. This method will verify the current id_token, if one |
| 786 |
* isn't provided. |
| 787 |
* |
| 788 |
* @throws LogicException If no token was provided and no token was set using `setAccessToken`. |
| 789 |
* @throws UnexpectedValueException If the token is not a valid JWT. |
| 790 |
* @param string|null $idToken The token (id_token) that should be verified. |
| 791 |
* @return array|false Returns the token payload as an array if the verification was |
| 792 |
* successful, false otherwise. |
| 793 |
*/ |
| 794 |
public function verifyIdToken($idToken = null) |
| 795 |
{ |
| 796 |
$tokenVerifier = new Verify( |
| 797 |
$this->getHttpClient(), |
| 798 |
$this->getCache(), |
| 799 |
$this->config['jwt'] |
| 800 |
); |
| 801 |
|
| 802 |
if (null === $idToken) { |
| 803 |
$token = $this->getAccessToken(); |
| 804 |
if (!isset($token['id_token'])) { |
| 805 |
throw new LogicException( |
| 806 |
'id_token must be passed in or set as part of setAccessToken' |
| 807 |
); |
| 808 |
} |
| 809 |
$idToken = $token['id_token']; |
| 810 |
} |
| 811 |
|
| 812 |
return $tokenVerifier->verifyIdToken( |
| 813 |
$idToken, |
| 814 |
$this->getClientId() |
| 815 |
); |
| 816 |
} |
| 817 |
|
| 818 |
/** |
| 819 |
* Set the scopes to be requested. Must be called before createAuthUrl(). |
| 820 |
* Will remove any previously configured scopes. |
| 821 |
* @param string|array $scope_or_scopes, ie: |
| 822 |
* array( |
| 823 |
* 'https://www.googleapis.com/auth/plus.login', |
| 824 |
* 'https://www.googleapis.com/auth/moderator' |
| 825 |
* ); |
| 826 |
*/ |
| 827 |
public function setScopes($scope_or_scopes) |
| 828 |
{ |
| 829 |
$this->requestedScopes = []; |
| 830 |
$this->addScope($scope_or_scopes); |
| 831 |
} |
| 832 |
|
| 833 |
/** |
| 834 |
* This functions adds a scope to be requested as part of the OAuth2.0 flow. |
| 835 |
* Will append any scopes not previously requested to the scope parameter. |
| 836 |
* A single string will be treated as a scope to request. An array of strings |
| 837 |
* will each be appended. |
| 838 |
* @param string|string[] $scope_or_scopes e.g. "profile" |
| 839 |
*/ |
| 840 |
public function addScope($scope_or_scopes) |
| 841 |
{ |
| 842 |
if (is_string($scope_or_scopes) && !in_array($scope_or_scopes, $this->requestedScopes)) { |
| 843 |
$this->requestedScopes[] = $scope_or_scopes; |
| 844 |
} elseif (is_array($scope_or_scopes)) { |
| 845 |
foreach ($scope_or_scopes as $scope) { |
| 846 |
$this->addScope($scope); |
| 847 |
} |
| 848 |
} |
| 849 |
} |
| 850 |
|
| 851 |
/** |
| 852 |
* Returns the list of scopes requested by the client |
| 853 |
* @return array the list of scopes |
| 854 |
* |
| 855 |
*/ |
| 856 |
public function getScopes() |
| 857 |
{ |
| 858 |
return $this->requestedScopes; |
| 859 |
} |
| 860 |
|
| 861 |
/** |
| 862 |
* @return string|null |
| 863 |
* @visible For Testing |
| 864 |
*/ |
| 865 |
public function prepareScopes() |
| 866 |
{ |
| 867 |
if (empty($this->requestedScopes)) { |
| 868 |
return null; |
| 869 |
} |
| 870 |
|
| 871 |
return implode(' ', $this->requestedScopes); |
| 872 |
} |
| 873 |
|
| 874 |
/** |
| 875 |
* Helper method to execute deferred HTTP requests. |
| 876 |
* |
| 877 |
* @template T |
| 878 |
* @param RequestInterface $request |
| 879 |
* @param class-string<T>|false|null $expectedClass |
| 880 |
* @throws \Google\Exception |
| 881 |
* @return mixed|T|ResponseInterface |
| 882 |
*/ |
| 883 |
public function execute(RequestInterface $request, $expectedClass = null) |
| 884 |
{ |
| 885 |
$request = $request |
| 886 |
->withHeader( |
| 887 |
'User-Agent', |
| 888 |
sprintf( |
| 889 |
'%s %s%s', |
| 890 |
$this->config['application_name'], |
| 891 |
self::USER_AGENT_SUFFIX, |
| 892 |
$this->getLibraryVersion() |
| 893 |
) |
| 894 |
) |
| 895 |
->withHeader( |
| 896 |
'x-goog-api-client', |
| 897 |
sprintf( |
| 898 |
'gl-php/%s gdcl/%s', |
| 899 |
phpversion(), |
| 900 |
$this->getLibraryVersion() |
| 901 |
) |
| 902 |
); |
| 903 |
|
| 904 |
if ($this->config['api_format_v2']) { |
| 905 |
$request = $request->withHeader( |
| 906 |
'X-GOOG-API-FORMAT-VERSION', |
| 907 |
'2' |
| 908 |
); |
| 909 |
} |
| 910 |
|
| 911 |
// call the authorize method |
| 912 |
// this is where most of the grunt work is done |
| 913 |
$http = $this->authorize(); |
| 914 |
|
| 915 |
return REST::execute( |
| 916 |
$http, |
| 917 |
$request, |
| 918 |
$expectedClass, |
| 919 |
$this->config['retry'], |
| 920 |
$this->config['retry_map'] |
| 921 |
); |
| 922 |
} |
| 923 |
|
| 924 |
/** |
| 925 |
* Declare whether batch calls should be used. This may increase throughput |
| 926 |
* by making multiple requests in one connection. |
| 927 |
* |
| 928 |
* @param boolean $useBatch True if the batch support should |
| 929 |
* be enabled. Defaults to False. |
| 930 |
*/ |
| 931 |
public function setUseBatch($useBatch) |
| 932 |
{ |
| 933 |
// This is actually an alias for setDefer. |
| 934 |
$this->setDefer($useBatch); |
| 935 |
} |
| 936 |
|
| 937 |
/** |
| 938 |
* Are we running in Google AppEngine? |
| 939 |
* return bool |
| 940 |
*/ |
| 941 |
public function isAppEngine() |
| 942 |
{ |
| 943 |
return (isset($_SERVER['SERVER_SOFTWARE']) && |
| 944 |
strpos($_SERVER['SERVER_SOFTWARE'], 'Google App Engine') !== false); |
| 945 |
} |
| 946 |
|
| 947 |
public function setConfig($name, $value) |
| 948 |
{ |
| 949 |
$this->config[$name] = $value; |
| 950 |
} |
| 951 |
|
| 952 |
public function getConfig($name, $default = null) |
| 953 |
{ |
| 954 |
return isset($this->config[$name]) ? $this->config[$name] : $default; |
| 955 |
} |
| 956 |
|
| 957 |
/** |
| 958 |
* For backwards compatibility |
| 959 |
* alias for setAuthConfig |
| 960 |
* |
| 961 |
* @param string $file the configuration file |
| 962 |
* @throws \Google\Exception |
| 963 |
* @deprecated |
| 964 |
*/ |
| 965 |
public function setAuthConfigFile($file) |
| 966 |
{ |
| 967 |
$this->setAuthConfig($file); |
| 968 |
} |
| 969 |
|
| 970 |
/** |
| 971 |
* Set the auth config from new or deprecated JSON config. |
| 972 |
* This structure should match the file downloaded from |
| 973 |
* the "Download JSON" button on in the Google Developer |
| 974 |
* Console. |
| 975 |
* @param string|array $config the configuration json |
| 976 |
* @throws \Google\Exception |
| 977 |
*/ |
| 978 |
public function setAuthConfig($config) |
| 979 |
{ |
| 980 |
if (is_string($config)) { |
| 981 |
if (!file_exists($config)) { |
| 982 |
throw new InvalidArgumentException(sprintf('file "%s" does not exist', $config)); |
| 983 |
} |
| 984 |
|
| 985 |
$json = file_get_contents($config); |
| 986 |
|
| 987 |
if (!$config = json_decode($json, true)) { |
| 988 |
throw new LogicException('invalid json for auth config'); |
| 989 |
} |
| 990 |
} |
| 991 |
|
| 992 |
$key = isset($config['installed']) ? 'installed' : 'web'; |
| 993 |
if (isset($config['type']) && $config['type'] == 'service_account') { |
| 994 |
// application default credentials |
| 995 |
$this->useApplicationDefaultCredentials(); |
| 996 |
|
| 997 |
// set the information from the config |
| 998 |
$this->setClientId($config['client_id']); |
| 999 |
$this->config['client_email'] = $config['client_email']; |
| 1000 |
$this->config['signing_key'] = $config['private_key']; |
| 1001 |
$this->config['signing_algorithm'] = 'HS256'; |
| 1002 |
} elseif (isset($config[$key])) { |
| 1003 |
// old-style |
| 1004 |
$this->setClientId($config[$key]['client_id']); |
| 1005 |
$this->setClientSecret($config[$key]['client_secret']); |
| 1006 |
if (isset($config[$key]['redirect_uris'])) { |
| 1007 |
$this->setRedirectUri($config[$key]['redirect_uris'][0]); |
| 1008 |
} |
| 1009 |
} else { |
| 1010 |
// new-style |
| 1011 |
$this->setClientId($config['client_id']); |
| 1012 |
$this->setClientSecret($config['client_secret']); |
| 1013 |
if (isset($config['redirect_uris'])) { |
| 1014 |
$this->setRedirectUri($config['redirect_uris'][0]); |
| 1015 |
} |
| 1016 |
} |
| 1017 |
} |
| 1018 |
|
| 1019 |
/** |
| 1020 |
* Use when the service account has been delegated domain wide access. |
| 1021 |
* |
| 1022 |
* @param string $subject an email address account to impersonate |
| 1023 |
*/ |
| 1024 |
public function setSubject($subject) |
| 1025 |
{ |
| 1026 |
$this->config['subject'] = $subject; |
| 1027 |
} |
| 1028 |
|
| 1029 |
/** |
| 1030 |
* Declare whether making API calls should make the call immediately, or |
| 1031 |
* return a request which can be called with ->execute(); |
| 1032 |
* |
| 1033 |
* @param boolean $defer True if calls should not be executed right away. |
| 1034 |
*/ |
| 1035 |
public function setDefer($defer) |
| 1036 |
{ |
| 1037 |
$this->deferExecution = $defer; |
| 1038 |
} |
| 1039 |
|
| 1040 |
/** |
| 1041 |
* Whether or not to return raw requests |
| 1042 |
* @return boolean |
| 1043 |
*/ |
| 1044 |
public function shouldDefer() |
| 1045 |
{ |
| 1046 |
return $this->deferExecution; |
| 1047 |
} |
| 1048 |
|
| 1049 |
/** |
| 1050 |
* @return OAuth2 implementation |
| 1051 |
*/ |
| 1052 |
public function getOAuth2Service() |
| 1053 |
{ |
| 1054 |
if (!isset($this->auth)) { |
| 1055 |
$this->auth = $this->createOAuth2Service(); |
| 1056 |
} |
| 1057 |
|
| 1058 |
return $this->auth; |
| 1059 |
} |
| 1060 |
|
| 1061 |
/** |
| 1062 |
* create a default google auth object |
| 1063 |
*/ |
| 1064 |
protected function createOAuth2Service() |
| 1065 |
{ |
| 1066 |
$auth = new OAuth2([ |
| 1067 |
'clientId' => $this->getClientId(), |
| 1068 |
'clientSecret' => $this->getClientSecret(), |
| 1069 |
'authorizationUri' => self::OAUTH2_AUTH_URL, |
| 1070 |
'tokenCredentialUri' => self::OAUTH2_TOKEN_URI, |
| 1071 |
'redirectUri' => $this->getRedirectUri(), |
| 1072 |
'issuer' => $this->config['client_id'], |
| 1073 |
'signingKey' => $this->config['signing_key'], |
| 1074 |
'signingAlgorithm' => $this->config['signing_algorithm'], |
| 1075 |
]); |
| 1076 |
|
| 1077 |
return $auth; |
| 1078 |
} |
| 1079 |
|
| 1080 |
/** |
| 1081 |
* Set the Cache object |
| 1082 |
* @param CacheItemPoolInterface $cache |
| 1083 |
*/ |
| 1084 |
public function setCache(CacheItemPoolInterface $cache) |
| 1085 |
{ |
| 1086 |
$this->cache = $cache; |
| 1087 |
} |
| 1088 |
|
| 1089 |
/** |
| 1090 |
* @return CacheItemPoolInterface |
| 1091 |
*/ |
| 1092 |
public function getCache() |
| 1093 |
{ |
| 1094 |
if (!$this->cache) { |
| 1095 |
$this->cache = $this->createDefaultCache(); |
| 1096 |
} |
| 1097 |
|
| 1098 |
return $this->cache; |
| 1099 |
} |
| 1100 |
|
| 1101 |
/** |
| 1102 |
* @param array $cacheConfig |
| 1103 |
*/ |
| 1104 |
public function setCacheConfig(array $cacheConfig) |
| 1105 |
{ |
| 1106 |
$this->config['cache_config'] = $cacheConfig; |
| 1107 |
} |
| 1108 |
|
| 1109 |
/** |
| 1110 |
* Set the Logger object |
| 1111 |
* @param LoggerInterface $logger |
| 1112 |
*/ |
| 1113 |
public function setLogger(LoggerInterface $logger) |
| 1114 |
{ |
| 1115 |
$this->logger = $logger; |
| 1116 |
} |
| 1117 |
|
| 1118 |
/** |
| 1119 |
* @return LoggerInterface |
| 1120 |
*/ |
| 1121 |
public function getLogger() |
| 1122 |
{ |
| 1123 |
if (!isset($this->logger)) { |
| 1124 |
$this->logger = $this->createDefaultLogger(); |
| 1125 |
} |
| 1126 |
|
| 1127 |
return $this->logger; |
| 1128 |
} |
| 1129 |
|
| 1130 |
protected function createDefaultLogger() |
| 1131 |
{ |
| 1132 |
$logger = new Logger('google-api-php-client'); |
| 1133 |
if ($this->isAppEngine()) { |
| 1134 |
$handler = new MonologSyslogHandler('app', LOG_USER, Logger::NOTICE); |
| 1135 |
} else { |
| 1136 |
$handler = new MonologStreamHandler('php://stderr', Logger::NOTICE); |
| 1137 |
} |
| 1138 |
$logger->pushHandler($handler); |
| 1139 |
|
| 1140 |
return $logger; |
| 1141 |
} |
| 1142 |
|
| 1143 |
protected function createDefaultCache() |
| 1144 |
{ |
| 1145 |
return new MemoryCacheItemPool(); |
| 1146 |
} |
| 1147 |
|
| 1148 |
/** |
| 1149 |
* Set the Http Client object |
| 1150 |
* @param ClientInterface $http |
| 1151 |
*/ |
| 1152 |
public function setHttpClient(ClientInterface $http) |
| 1153 |
{ |
| 1154 |
$this->http = $http; |
| 1155 |
} |
| 1156 |
|
| 1157 |
/** |
| 1158 |
* @return ClientInterface |
| 1159 |
*/ |
| 1160 |
public function getHttpClient() |
| 1161 |
{ |
| 1162 |
if (null === $this->http) { |
| 1163 |
$this->http = $this->createDefaultHttpClient(); |
| 1164 |
} |
| 1165 |
|
| 1166 |
return $this->http; |
| 1167 |
} |
| 1168 |
|
| 1169 |
/** |
| 1170 |
* Set the API format version. |
| 1171 |
* |
| 1172 |
* `true` will use V2, which may return more useful error messages. |
| 1173 |
* |
| 1174 |
* @param bool $value |
| 1175 |
*/ |
| 1176 |
public function setApiFormatV2($value) |
| 1177 |
{ |
| 1178 |
$this->config['api_format_v2'] = (bool) $value; |
| 1179 |
} |
| 1180 |
|
| 1181 |
protected function createDefaultHttpClient() |
| 1182 |
{ |
| 1183 |
$guzzleVersion = null; |
| 1184 |
if (defined('\GuzzleHttp\ClientInterface::MAJOR_VERSION')) { |
| 1185 |
$guzzleVersion = ClientInterface::MAJOR_VERSION; |
| 1186 |
} elseif (defined('\GuzzleHttp\ClientInterface::VERSION')) { |
| 1187 |
// @phpstan-ignore-next-line |
| 1188 |
$guzzleVersion = (int)substr(ClientInterface::VERSION, 0, 1); |
| 1189 |
} |
| 1190 |
|
| 1191 |
if (5 === $guzzleVersion) { |
| 1192 |
$options = [ |
| 1193 |
'base_url' => $this->config['base_path'], |
| 1194 |
'defaults' => ['exceptions' => false], |
| 1195 |
]; |
| 1196 |
if ($this->isAppEngine()) { |
| 1197 |
if (class_exists(StreamHandler::class)) { |
| 1198 |
// set StreamHandler on AppEngine by default |
| 1199 |
$options['handler'] = new StreamHandler(); |
| 1200 |
$options['defaults']['verify'] = '/etc/ca-certificates.crt'; |
| 1201 |
} |
| 1202 |
} |
| 1203 |
} elseif (6 === $guzzleVersion || 7 === $guzzleVersion) { |
| 1204 |
// guzzle 6 or 7 |
| 1205 |
$options = [ |
| 1206 |
'base_uri' => $this->config['base_path'], |
| 1207 |
'http_errors' => false, |
| 1208 |
]; |
| 1209 |
} else { |
| 1210 |
throw new LogicException('Could not find supported version of Guzzle.'); |
| 1211 |
} |
| 1212 |
|
| 1213 |
return new GuzzleClient($options); |
| 1214 |
} |
| 1215 |
|
| 1216 |
/** |
| 1217 |
* @return FetchAuthTokenCache |
| 1218 |
*/ |
| 1219 |
private function createApplicationDefaultCredentials() |
| 1220 |
{ |
| 1221 |
$scopes = $this->prepareScopes(); |
| 1222 |
$sub = $this->config['subject']; |
| 1223 |
$signingKey = $this->config['signing_key']; |
| 1224 |
|
| 1225 |
// create credentials using values supplied in setAuthConfig |
| 1226 |
if ($signingKey) { |
| 1227 |
$serviceAccountCredentials = [ |
| 1228 |
'client_id' => $this->config['client_id'], |
| 1229 |
'client_email' => $this->config['client_email'], |
| 1230 |
'private_key' => $signingKey, |
| 1231 |
'type' => 'service_account', |
| 1232 |
'quota_project_id' => $this->config['quota_project'], |
| 1233 |
]; |
| 1234 |
$credentials = CredentialsLoader::makeCredentials( |
| 1235 |
$scopes, |
| 1236 |
$serviceAccountCredentials |
| 1237 |
); |
| 1238 |
} else { |
| 1239 |
// When $sub is provided, we cannot pass cache classes to ::getCredentials |
| 1240 |
// because FetchAuthTokenCache::setSub does not exist. |
| 1241 |
// The result is when $sub is provided, calls to ::onGce are not cached. |
| 1242 |
$credentials = ApplicationDefaultCredentials::getCredentials( |
| 1243 |
$scopes, |
| 1244 |
null, |
| 1245 |
$sub ? null : $this->config['cache_config'], |
| 1246 |
$sub ? null : $this->getCache(), |
| 1247 |
$this->config['quota_project'] |
| 1248 |
); |
| 1249 |
} |
| 1250 |
|
| 1251 |
// for service account domain-wide authority (impersonating a user) |
| 1252 |
// @see https://developers.google.com/identity/protocols/OAuth2ServiceAccount |
| 1253 |
if ($sub) { |
| 1254 |
if (!$credentials instanceof ServiceAccountCredentials) { |
| 1255 |
throw new DomainException('domain-wide authority requires service account credentials'); |
| 1256 |
} |
| 1257 |
|
| 1258 |
$credentials->setSub($sub); |
| 1259 |
} |
| 1260 |
|
| 1261 |
// If we are not using FetchAuthTokenCache yet, create it now |
| 1262 |
if (!$credentials instanceof FetchAuthTokenCache) { |
| 1263 |
$credentials = new FetchAuthTokenCache( |
| 1264 |
$credentials, |
| 1265 |
$this->config['cache_config'], |
| 1266 |
$this->getCache() |
| 1267 |
); |
| 1268 |
} |
| 1269 |
return $credentials; |
| 1270 |
} |
| 1271 |
|
| 1272 |
protected function getAuthHandler() |
| 1273 |
{ |
| 1274 |
// Be very careful using the cache, as the underlying auth library's cache |
| 1275 |
// implementation is naive, and the cache keys do not account for user |
| 1276 |
// sessions. |
| 1277 |
// |
| 1278 |
// @see https://github.com/google/google-api-php-client/issues/821 |
| 1279 |
return AuthHandlerFactory::build( |
| 1280 |
$this->getCache(), |
| 1281 |
$this->config['cache_config'] |
| 1282 |
); |
| 1283 |
} |
| 1284 |
|
| 1285 |
private function createUserRefreshCredentials($scope, $refreshToken) |
| 1286 |
{ |
| 1287 |
$creds = array_filter([ |
| 1288 |
'client_id' => $this->getClientId(), |
| 1289 |
'client_secret' => $this->getClientSecret(), |
| 1290 |
'refresh_token' => $refreshToken, |
| 1291 |
]); |
| 1292 |
|
| 1293 |
return new UserRefreshCredentials($scope, $creds); |
| 1294 |
} |
| 1295 |
} |
| 1296 |
|