Permalink
Find file Copy path
1139 lines (1007 sloc) 31.5 KB
<?php
/*
* Copyright 2010 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
use Google\Auth\ApplicationDefaultCredentials;
use Google\Auth\Cache\MemoryCacheItemPool;
use Google\Auth\CredentialsLoader;
use Google\Auth\HttpHandler\HttpHandlerFactory;
use Google\Auth\OAuth2;
use Google\Auth\Credentials\ServiceAccountCredentials;
use Google\Auth\Credentials\UserRefreshCredentials;
use GuzzleHttp\Client;
use GuzzleHttp\ClientInterface;
use GuzzleHttp\Ring\Client\StreamHandler;
use Psr\Cache\CacheItemPoolInterface;
use Psr\Http\Message\RequestInterface;
use Psr\Log\LoggerInterface;
use Monolog\Logger;
use Monolog\Handler\StreamHandler as MonologStreamHandler;
use Monolog\Handler\SyslogHandler as MonologSyslogHandler;
/**
* The Google API Client
* https://github.com/google/google-api-php-client
*/
class Google_Client
{
const LIBVER = "2.2.2";
const USER_AGENT_SUFFIX = "google-api-php-client/";
const OAUTH2_REVOKE_URI = 'https://oauth2.googleapis.com/revoke';
const OAUTH2_TOKEN_URI = 'https://oauth2.googleapis.com/token';
const OAUTH2_AUTH_URL = 'https://accounts.google.com/o/oauth2/auth';
const API_BASE_PATH = 'https://www.googleapis.com';
/**
* @var Google\Auth\OAuth2 $auth
*/
private $auth;
/**
* @var GuzzleHttp\ClientInterface $http
*/
private $http;
/**
* @var Psr\Cache\CacheItemPoolInterface $cache
*/
private $cache;
/**
* @var array access token
*/
private $token;
/**
* @var array $config
*/
private $config;
/**
* @var Psr\Log\LoggerInterface $logger
*/
private $logger;
/**
* @var boolean $deferExecution
*/
private $deferExecution = false;
/** @var array $scopes */
// Scopes requested by the client
protected $requestedScopes = [];
/**
* Construct the Google Client.
*
* @param array $config
*/
public function __construct(array $config = array())
{
$this->config = array_merge(
[
'application_name' => '',
// Don't change these unless you're working against a special development
// or testing environment.
'base_path' => self::API_BASE_PATH,
// https://developers.google.com/console
'client_id' => '',
'client_secret' => '',
'redirect_uri' => null,
'state' => null,
// Simple API access key, also from the API console. Ensure you get
// a Server key, and not a Browser key.
'developer_key' => '',
// For use with Google Cloud Platform
// fetch the ApplicationDefaultCredentials, if applicable
// @see https://developers.google.com/identity/protocols/application-default-credentials
'use_application_default_credentials' => false,
'signing_key' => null,
'signing_algorithm' => null,
'subject' => null,
// Other OAuth2 parameters.
'hd' => '',
'prompt' => '',
'openid.realm' => '',
'include_granted_scopes' => null,
'login_hint' => '',
'request_visible_actions' => '',
'access_type' => 'online',
'approval_prompt' => 'auto',
// Task Runner retry configuration
// @see Google_Task_Runner
'retry' => array(),
'retry_map' => null,
// cache config for downstream auth caching
'cache_config' => [],
// function to be called when an access token is fetched
// follows the signature function ($cacheKey, $accessToken)
'token_callback' => null,
// Service class used in Google_Client::verifyIdToken.
// Explicitly pass this in to avoid setting JWT::$leeway
'jwt' => null,
],
$config
);
}
/**
* Get a string containing the version of the library.
*
* @return string
*/
public function getLibraryVersion()
{
return self::LIBVER;
}
/**
* For backwards compatibility
* alias for fetchAccessTokenWithAuthCode
*
* @param $code string code from accounts.google.com
* @return array access token
* @deprecated
*/
public function authenticate($code)
{
return $this->fetchAccessTokenWithAuthCode($code);
}
/**
* Attempt to exchange a code for an valid authentication token.
* Helper wrapped around the OAuth 2.0 implementation.
*
* @param $code string code from accounts.google.com
* @return array access token
*/
public function fetchAccessTokenWithAuthCode($code)
{
if (strlen($code) == 0) {
throw new InvalidArgumentException("Invalid code");
}
$auth = $this->getOAuth2Service();
$auth->setCode($code);
$auth->setRedirectUri($this->getRedirectUri());
$httpHandler = HttpHandlerFactory::build($this->getHttpClient());
$creds = $auth->fetchAuthToken($httpHandler);
if ($creds && isset($creds['access_token'])) {
$creds['created'] = time();
$this->setAccessToken($creds);
}
return $creds;
}
/**
* For backwards compatibility
* alias for fetchAccessTokenWithAssertion
*
* @return array access token
* @deprecated
*/
public function refreshTokenWithAssertion()
{
return $this->fetchAccessTokenWithAssertion();
}
/**
* Fetches a fresh access token with a given assertion token.
* @param ClientInterface $authHttp optional.
* @return array access token
*/
public function fetchAccessTokenWithAssertion(ClientInterface $authHttp = null)
{
if (!$this->isUsingApplicationDefaultCredentials()) {
throw new DomainException(
'set the JSON service account credentials using'
. ' Google_Client::setAuthConfig or set the path to your JSON file'
. ' with the "GOOGLE_APPLICATION_CREDENTIALS" environment variable'
. ' and call Google_Client::useApplicationDefaultCredentials to'
. ' refresh a token with assertion.'
);
}
$this->getLogger()->log(
'info',
'OAuth2 access token refresh with Signed JWT assertion grants.'
);
$credentials = $this->createApplicationDefaultCredentials();
$httpHandler = HttpHandlerFactory::build($authHttp);
$creds = $credentials->fetchAuthToken($httpHandler);
if ($creds && isset($creds['access_token'])) {
$creds['created'] = time();
$this->setAccessToken($creds);
}
return $creds;
}
/**
* For backwards compatibility
* alias for fetchAccessTokenWithRefreshToken
*
* @param string $refreshToken
* @return array access token
*/
public function refreshToken($refreshToken)
{
return $this->fetchAccessTokenWithRefreshToken($refreshToken);
}
/**
* Fetches a fresh OAuth 2.0 access token with the given refresh token.
* @param string $refreshToken
* @return array access token
*/
public function fetchAccessTokenWithRefreshToken($refreshToken = null)
{
if (null === $refreshToken) {
if (!isset($this->token['refresh_token'])) {
throw new LogicException(
'refresh token must be passed in or set as part of setAccessToken'
);
}
$refreshToken = $this->token['refresh_token'];
}
$this->getLogger()->info('OAuth2 access token refresh');
$auth = $this->getOAuth2Service();
$auth->setRefreshToken($refreshToken);
$httpHandler = HttpHandlerFactory::build($this->getHttpClient());
$creds = $auth->fetchAuthToken($httpHandler);
if ($creds && isset($creds['access_token'])) {
$creds['created'] = time();
if (!isset($creds['refresh_token'])) {
$creds['refresh_token'] = $refreshToken;
}
$this->setAccessToken($creds);
}
return $creds;
}
/**
* Create a URL to obtain user authorization.
* The authorization endpoint allows the user to first
* authenticate, and then grant/deny the access request.
* @param string|array $scope The scope is expressed as an array or list of space-delimited strings.
* @return string
*/
public function createAuthUrl($scope = null)
{
if (empty($scope)) {
$scope = $this->prepareScopes();
}
if (is_array($scope)) {
$scope = implode(' ', $scope);
}
// only accept one of prompt or approval_prompt
$approvalPrompt = $this->config['prompt']
? null
: $this->config['approval_prompt'];
// include_granted_scopes should be string "true", string "false", or null
$includeGrantedScopes = $this->config['include_granted_scopes'] === null
? null
: var_export($this->config['include_granted_scopes'], true);
$params = array_filter(
[
'access_type' => $this->config['access_type'],
'approval_prompt' => $approvalPrompt,
'hd' => $this->config['hd'],
'include_granted_scopes' => $includeGrantedScopes,
'login_hint' => $this->config['login_hint'],
'openid.realm' => $this->config['openid.realm'],
'prompt' => $this->config['prompt'],
'response_type' => 'code',
'scope' => $scope,
'state' => $this->config['state'],
]
);
// If the list of scopes contains plus.login, add request_visible_actions
// to auth URL.
$rva = $this->config['request_visible_actions'];
if (strlen($rva) > 0 && false !== strpos($scope, 'plus.login')) {
$params['request_visible_actions'] = $rva;
}
$auth = $this->getOAuth2Service();
return (string) $auth->buildFullAuthorizationUri($params);
}
/**
* Adds auth listeners to the HTTP client based on the credentials
* set in the Google API Client object
*
* @param GuzzleHttp\ClientInterface $http the http client object.
* @return GuzzleHttp\ClientInterface the http client object
*/
public function authorize(ClientInterface $http = null)
{
$credentials = null;
$token = null;
$scopes = null;
if (null === $http) {
$http = $this->getHttpClient();
}
// These conditionals represent the decision tree for authentication
// 1. Check for Application Default Credentials
// 2. Check for API Key
// 3a. Check for an Access Token
// 3b. If access token exists but is expired, try to refresh it
if ($this->isUsingApplicationDefaultCredentials()) {
$credentials = $this->createApplicationDefaultCredentials();
} elseif ($token = $this->getAccessToken()) {
$scopes = $this->prepareScopes();
// add refresh subscriber to request a new token
if (isset($token['refresh_token']) && $this->isAccessTokenExpired()) {
$credentials = $this->createUserRefreshCredentials(
$scopes,
$token['refresh_token']
);
}
}
$authHandler = $this->getAuthHandler();
if ($credentials) {
$callback = $this->config['token_callback'];
$http = $authHandler->attachCredentials($http, $credentials, $callback);
} elseif ($token) {
$http = $authHandler->attachToken($http, $token, (array) $scopes);
} elseif ($key = $this->config['developer_key']) {
$http = $authHandler->attachKey($http, $key);
}
return $http;
}
/**
* Set the configuration to use application default credentials for
* authentication
*
* @see https://developers.google.com/identity/protocols/application-default-credentials
* @param boolean $useAppCreds
*/
public function useApplicationDefaultCredentials($useAppCreds = true)
{
$this->config['use_application_default_credentials'] = $useAppCreds;
}
/**
* To prevent useApplicationDefaultCredentials from inappropriately being
* called in a conditional
*
* @see https://developers.google.com/identity/protocols/application-default-credentials
*/
public function isUsingApplicationDefaultCredentials()
{
return $this->config['use_application_default_credentials'];
}
/**
* @param string|array $token
* @throws InvalidArgumentException
*/
public function setAccessToken($token)
{
if (is_string($token)) {
if ($json = json_decode($token, true)) {
$token = $json;
} else {
// assume $token is just the token string
$token = array(
'access_token' => $token,
);
}
}
if ($token == null) {
throw new InvalidArgumentException('invalid json token');
}
if (!isset($token['access_token'])) {
throw new InvalidArgumentException("Invalid token format");
}
$this->token = $token;
}
public function getAccessToken()
{
return $this->token;
}
/**
* @return string|null
*/
public function getRefreshToken()
{
if (isset($this->token['refresh_token'])) {
return $this->token['refresh_token'];
}
return null;
}
/**
* Returns if the access_token is expired.
* @return bool Returns True if the access_token is expired.
*/
public function isAccessTokenExpired()
{
if (!$this->token) {
return true;
}
$created = 0;
if (isset($this->token['created'])) {
$created = $this->token['created'];
} elseif (isset($this->token['id_token'])) {
// check the ID token for "iat"
// signature verification is not required here, as we are just
// using this for convenience to save a round trip request
// to the Google API server
$idToken = $this->token['id_token'];
if (substr_count($idToken, '.') == 2) {
$parts = explode('.', $idToken);
$payload = json_decode(base64_decode($parts[1]), true);
if ($payload && isset($payload['iat'])) {
$created = $payload['iat'];
}
}
}
// If the token is set to expire in the next 30 seconds.
return ($created + ($this->token['expires_in'] - 30)) < time();
}
/**
* @deprecated See UPGRADING.md for more information
*/
public function getAuth()
{
throw new BadMethodCallException(
'This function no longer exists. See UPGRADING.md for more information'
);
}
/**
* @deprecated See UPGRADING.md for more information
*/
public function setAuth($auth)
{
throw new BadMethodCallException(
'This function no longer exists. See UPGRADING.md for more information'
);
}
/**
* Set the OAuth 2.0 Client ID.
* @param string $clientId
*/
public function setClientId($clientId)
{
$this->config['client_id'] = $clientId;
}
public function getClientId()
{
return $this->config['client_id'];
}
/**
* Set the OAuth 2.0 Client Secret.
* @param string $clientSecret
*/
public function setClientSecret($clientSecret)
{
$this->config['client_secret'] = $clientSecret;
}
public function getClientSecret()
{
return $this->config['client_secret'];
}
/**
* Set the OAuth 2.0 Redirect URI.
* @param string $redirectUri
*/
public function setRedirectUri($redirectUri)
{
$this->config['redirect_uri'] = $redirectUri;
}
public function getRedirectUri()
{
return $this->config['redirect_uri'];
}
/**
* Set OAuth 2.0 "state" parameter to achieve per-request customization.
* @see http://tools.ietf.org/html/draft-ietf-oauth-v2-22#section-3.1.2.2
* @param string $state
*/
public function setState($state)
{
$this->config['state'] = $state;
}
/**
* @param string $accessType Possible values for access_type include:
* {@code "offline"} to request offline access from the user.
* {@code "online"} to request online access from the user.
*/
public function setAccessType($accessType)
{
$this->config['access_type'] = $accessType;
}
/**
* @param string $approvalPrompt Possible values for approval_prompt include:
* {@code "force"} to force the approval UI to appear.
* {@code "auto"} to request auto-approval when possible. (This is the default value)
*/
public function setApprovalPrompt($approvalPrompt)
{
$this->config['approval_prompt'] = $approvalPrompt;
}
/**
* Set the login hint, email address or sub id.
* @param string $loginHint
*/
public function setLoginHint($loginHint)
{
$this->config['login_hint'] = $loginHint;
}
/**
* Set the application name, this is included in the User-Agent HTTP header.
* @param string $applicationName
*/
public function setApplicationName($applicationName)
{
$this->config['application_name'] = $applicationName;
}
/**
* If 'plus.login' is included in the list of requested scopes, you can use
* this method to define types of app activities that your app will write.
* You can find a list of available types here:
* @link https://developers.google.com/+/api/moment-types
*
* @param array $requestVisibleActions Array of app activity types
*/
public function setRequestVisibleActions($requestVisibleActions)
{
if (is_array($requestVisibleActions)) {
$requestVisibleActions = implode(" ", $requestVisibleActions);
}
$this->config['request_visible_actions'] = $requestVisibleActions;
}
/**
* Set the developer key to use, these are obtained through the API Console.
* @see http://code.google.com/apis/console-help/#generatingdevkeys
* @param string $developerKey
*/
public function setDeveloperKey($developerKey)
{
$this->config['developer_key'] = $developerKey;
}
/**
* Set the hd (hosted domain) parameter streamlines the login process for
* Google Apps hosted accounts. By including the domain of the user, you
* restrict sign-in to accounts at that domain.
* @param $hd string - the domain to use.
*/
public function setHostedDomain($hd)
{
$this->config['hd'] = $hd;
}
/**
* Set the prompt hint. Valid values are none, consent and select_account.
* If no value is specified and the user has not previously authorized
* access, then the user is shown a consent screen.
* @param $prompt string
* {@code "none"} Do not display any authentication or consent screens. Must not be specified with other values.
* {@code "consent"} Prompt the user for consent.
* {@code "select_account"} Prompt the user to select an account.
*/
public function setPrompt($prompt)
{
$this->config['prompt'] = $prompt;
}
/**
* openid.realm is a parameter from the OpenID 2.0 protocol, not from OAuth
* 2.0. It is used in OpenID 2.0 requests to signify the URL-space for which
* an authentication request is valid.
* @param $realm string - the URL-space to use.
*/
public function setOpenidRealm($realm)
{
$this->config['openid.realm'] = $realm;
}
/**
* If this is provided with the value true, and the authorization request is
* granted, the authorization will include any previous authorizations
* granted to this user/application combination for other scopes.
* @param $include boolean - the URL-space to use.
*/
public function setIncludeGrantedScopes($include)
{
$this->config['include_granted_scopes'] = $include;
}
/**
* sets function to be called when an access token is fetched
* @param callable $tokenCallback - function ($cacheKey, $accessToken)
*/
public function setTokenCallback(callable $tokenCallback)
{
$this->config['token_callback'] = $tokenCallback;
}
/**
* Revoke an OAuth2 access token or refresh token. This method will revoke the current access
* token, if a token isn't provided.
*
* @param string|null $token The token (access token or a refresh token) that should be revoked.
* @return boolean Returns True if the revocation was successful, otherwise False.
*/
public function revokeToken($token = null)
{
$tokenRevoker = new Google_AccessToken_Revoke(
$this->getHttpClient()
);
return $tokenRevoker->revokeToken($token ?: $this->getAccessToken());
}
/**
* Verify an id_token. This method will verify the current id_token, if one
* isn't provided.
*
* @throws LogicException
* @param string|null $idToken The token (id_token) that should be verified.
* @return array|false Returns the token payload as an array if the verification was
* successful, false otherwise.
*/
public function verifyIdToken($idToken = null)
{
$tokenVerifier = new Google_AccessToken_Verify(
$this->getHttpClient(),
$this->getCache(),
$this->config['jwt']
);
if (null === $idToken) {
$token = $this->getAccessToken();
if (!isset($token['id_token'])) {
throw new LogicException(
'id_token must be passed in or set as part of setAccessToken'
);
}
$idToken = $token['id_token'];
}
return $tokenVerifier->verifyIdToken(
$idToken,
$this->getClientId()
);
}
/**
* Set the scopes to be requested. Must be called before createAuthUrl().
* Will remove any previously configured scopes.
* @param string|array $scope_or_scopes, ie: array('https://www.googleapis.com/auth/plus.login',
* 'https://www.googleapis.com/auth/moderator')
*/
public function setScopes($scope_or_scopes)
{
$this->requestedScopes = array();
$this->addScope($scope_or_scopes);
}
/**
* This functions adds a scope to be requested as part of the OAuth2.0 flow.
* Will append any scopes not previously requested to the scope parameter.
* A single string will be treated as a scope to request. An array of strings
* will each be appended.
* @param $scope_or_scopes string|array e.g. "profile"
*/
public function addScope($scope_or_scopes)
{
if (is_string($scope_or_scopes) && !in_array($scope_or_scopes, $this->requestedScopes)) {
$this->requestedScopes[] = $scope_or_scopes;
} else if (is_array($scope_or_scopes)) {
foreach ($scope_or_scopes as $scope) {
$this->addScope($scope);
}
}
}
/**
* Returns the list of scopes requested by the client
* @return array the list of scopes
*
*/
public function getScopes()
{
return $this->requestedScopes;
}
/**
* @return string|null
* @visible For Testing
*/
public function prepareScopes()
{
if (empty($this->requestedScopes)) {
return null;
}
return implode(' ', $this->requestedScopes);
}
/**
* Helper method to execute deferred HTTP requests.
*
* @param $request Psr\Http\Message\RequestInterface|Google_Http_Batch
* @throws Google_Exception
* @return object of the type of the expected class or Psr\Http\Message\ResponseInterface.
*/
public function execute(RequestInterface $request, $expectedClass = null)
{
$request = $request->withHeader(
'User-Agent',
$this->config['application_name']
. " " . self::USER_AGENT_SUFFIX
. $this->getLibraryVersion()
);
// call the authorize method
// this is where most of the grunt work is done
$http = $this->authorize();
return Google_Http_REST::execute(
$http,
$request,
$expectedClass,
$this->config['retry'],
$this->config['retry_map']
);
}
/**
* Declare whether batch calls should be used. This may increase throughput
* by making multiple requests in one connection.
*
* @param boolean $useBatch True if the batch support should
* be enabled. Defaults to False.
*/
public function setUseBatch($useBatch)
{
// This is actually an alias for setDefer.
$this->setDefer($useBatch);
}
/**
* Are we running in Google AppEngine?
* return bool
*/
public function isAppEngine()
{
return (isset($_SERVER['SERVER_SOFTWARE']) &&
strpos($_SERVER['SERVER_SOFTWARE'], 'Google App Engine') !== false);
}
public function setConfig($name, $value)
{
$this->config[$name] = $value;
}
public function getConfig($name, $default = null)
{
return isset($this->config[$name]) ? $this->config[$name] : $default;
}
/**
* For backwards compatibility
* alias for setAuthConfig
*
* @param string $file the configuration file
* @throws Google_Exception
* @deprecated
*/
public function setAuthConfigFile($file)
{
$this->setAuthConfig($file);
}
/**
* Set the auth config from new or deprecated JSON config.
* This structure should match the file downloaded from
* the "Download JSON" button on in the Google Developer
* Console.
* @param string|array $config the configuration json
* @throws Google_Exception
*/
public function setAuthConfig($config)
{
if (is_string($config)) {
if (!file_exists($config)) {
throw new InvalidArgumentException('file does not exist');
}
$json = file_get_contents($config);
if (!$config = json_decode($json, true)) {
throw new LogicException('invalid json for auth config');
}
}
$key = isset($config['installed']) ? 'installed' : 'web';
if (isset($config['type']) && $config['type'] == 'service_account') {
// application default credentials
$this->useApplicationDefaultCredentials();
// set the information from the config
$this->setClientId($config['client_id']);
$this->config['client_email'] = $config['client_email'];
$this->config['signing_key'] = $config['private_key'];
$this->config['signing_algorithm'] = 'HS256';
} elseif (isset($config[$key])) {
// old-style
$this->setClientId($config[$key]['client_id']);
$this->setClientSecret($config[$key]['client_secret']);
if (isset($config[$key]['redirect_uris'])) {
$this->setRedirectUri($config[$key]['redirect_uris'][0]);
}
} else {
// new-style
$this->setClientId($config['client_id']);
$this->setClientSecret($config['client_secret']);
if (isset($config['redirect_uris'])) {
$this->setRedirectUri($config['redirect_uris'][0]);
}
}
}
/**
* Use when the service account has been delegated domain wide access.
*
* @param string $subject an email address account to impersonate
*/
public function setSubject($subject)
{
$this->config['subject'] = $subject;
}
/**
* Declare whether making API calls should make the call immediately, or
* return a request which can be called with ->execute();
*
* @param boolean $defer True if calls should not be executed right away.
*/
public function setDefer($defer)
{
$this->deferExecution = $defer;
}
/**
* Whether or not to return raw requests
* @return boolean
*/
public function shouldDefer()
{
return $this->deferExecution;
}
/**
* @return Google\Auth\OAuth2 implementation
*/
public function getOAuth2Service()
{
if (!isset($this->auth)) {
$this->auth = $this->createOAuth2Service();
}
return $this->auth;
}
/**
* create a default google auth object
*/
protected function createOAuth2Service()
{
$auth = new OAuth2(
[
'clientId' => $this->getClientId(),
'clientSecret' => $this->getClientSecret(),
'authorizationUri' => self::OAUTH2_AUTH_URL,
'tokenCredentialUri' => self::OAUTH2_TOKEN_URI,
'redirectUri' => $this->getRedirectUri(),
'issuer' => $this->config['client_id'],
'signingKey' => $this->config['signing_key'],
'signingAlgorithm' => $this->config['signing_algorithm'],
]
);
return $auth;
}
/**
* Set the Cache object
* @param Psr\Cache\CacheItemPoolInterface $cache
*/
public function setCache(CacheItemPoolInterface $cache)
{
$this->cache = $cache;
}
/**
* @return Psr\Cache\CacheItemPoolInterface Cache implementation
*/
public function getCache()
{
if (!$this->cache) {
$this->cache = $this->createDefaultCache();
}
return $this->cache;
}
/**
* @param array $cacheConfig
*/
public function setCacheConfig(array $cacheConfig)
{
$this->config['cache_config'] = $cacheConfig;
}
/**
* Set the Logger object
* @param Psr\Log\LoggerInterface $logger
*/
public function setLogger(LoggerInterface $logger)
{
$this->logger = $logger;
}
/**
* @return Psr\Log\LoggerInterface implementation
*/
public function getLogger()
{
if (!isset($this->logger)) {
$this->logger = $this->createDefaultLogger();
}
return $this->logger;
}
protected function createDefaultLogger()
{
$logger = new Logger('google-api-php-client');
if ($this->isAppEngine()) {
$handler = new MonologSyslogHandler('app', LOG_USER, Logger::NOTICE);
} else {
$handler = new MonologStreamHandler('php://stderr', Logger::NOTICE);
}
$logger->pushHandler($handler);
return $logger;
}
protected function createDefaultCache()
{
return new MemoryCacheItemPool;
}
/**
* Set the Http Client object
* @param GuzzleHttp\ClientInterface $http
*/
public function setHttpClient(ClientInterface $http)
{
$this->http = $http;
}
/**
* @return GuzzleHttp\ClientInterface implementation
*/
public function getHttpClient()
{
if (null === $this->http) {
$this->http = $this->createDefaultHttpClient();
}
return $this->http;
}
protected function createDefaultHttpClient()
{
$options = ['exceptions' => false];
$version = ClientInterface::VERSION;
if ('5' === $version[0]) {
$options = [
'base_url' => $this->config['base_path'],
'defaults' => $options,
];
if ($this->isAppEngine()) {
// set StreamHandler on AppEngine by default
$options['handler'] = new StreamHandler();
$options['defaults']['verify'] = '/etc/ca-certificates.crt';
}
} else {
// guzzle 6
$options['base_uri'] = $this->config['base_path'];
}
return new Client($options);
}
private function createApplicationDefaultCredentials()
{
$scopes = $this->prepareScopes();
$sub = $this->config['subject'];
$signingKey = $this->config['signing_key'];
// create credentials using values supplied in setAuthConfig
if ($signingKey) {
$serviceAccountCredentials = array(
'client_id' => $this->config['client_id'],
'client_email' => $this->config['client_email'],
'private_key' => $signingKey,
'type' => 'service_account',
);
$credentials = CredentialsLoader::makeCredentials($scopes, $serviceAccountCredentials);
} else {
$credentials = ApplicationDefaultCredentials::getCredentials($scopes);
}
// for service account domain-wide authority (impersonating a user)
// @see https://developers.google.com/identity/protocols/OAuth2ServiceAccount
if ($sub) {
if (!$credentials instanceof ServiceAccountCredentials) {
throw new DomainException('domain-wide authority requires service account credentials');
}
$credentials->setSub($sub);
}
return $credentials;
}
protected function getAuthHandler()
{
// Be very careful using the cache, as the underlying auth library's cache
// implementation is naive, and the cache keys do not account for user
// sessions.
//
// @see https://github.com/google/google-api-php-client/issues/821
return Google_AuthHandler_AuthHandlerFactory::build(
$this->getCache(),
$this->config['cache_config']
);
}
private function createUserRefreshCredentials($scope, $refreshToken)
{
$creds = array_filter(
array(
'client_id' => $this->getClientId(),
'client_secret' => $this->getClientSecret(),
'refresh_token' => $refreshToken,
)
);
return new UserRefreshCredentials($scope, $creds);
}
}