updated plugin WP Mail SMTP version 2.4.0

This commit is contained in:
2020-09-25 14:44:17 +00:00
committed by Gitium
parent 4f3d745449
commit 3053837189
673 changed files with 31869 additions and 65613 deletions

View File

@ -0,0 +1,388 @@
<?php
/*
* Copyright 2019 Google LLC
*
* 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.
*/
namespace WPMailSMTP\Vendor\Google\Auth;
use DateTime;
use Exception;
use WPMailSMTP\Vendor\Firebase\JWT\ExpiredException;
use WPMailSMTP\Vendor\Firebase\JWT\JWT;
use WPMailSMTP\Vendor\Firebase\JWT\SignatureInvalidException;
use WPMailSMTP\Vendor\Google\Auth\Cache\MemoryCacheItemPool;
use WPMailSMTP\Vendor\Google\Auth\HttpHandler\HttpClientCache;
use WPMailSMTP\Vendor\Google\Auth\HttpHandler\HttpHandlerFactory;
use WPMailSMTP\Vendor\GuzzleHttp\Psr7;
use WPMailSMTP\Vendor\GuzzleHttp\Psr7\Request;
use InvalidArgumentException;
use WPMailSMTP\Vendor\phpseclib\Crypt\RSA;
use WPMailSMTP\Vendor\phpseclib\Math\BigInteger;
use WPMailSMTP\Vendor\Psr\Cache\CacheItemPoolInterface;
use RuntimeException;
use WPMailSMTP\Vendor\SimpleJWT\InvalidTokenException;
use WPMailSMTP\Vendor\SimpleJWT\JWT as SimpleJWT;
use WPMailSMTP\Vendor\SimpleJWT\Keys\KeyFactory;
use WPMailSMTP\Vendor\SimpleJWT\Keys\KeySet;
use UnexpectedValueException;
/**
* Wrapper around Google Access Tokens which provides convenience functions.
*
* @experimental
*/
class AccessToken
{
const FEDERATED_SIGNON_CERT_URL = 'https://www.googleapis.com/oauth2/v3/certs';
const IAP_CERT_URL = 'https://www.gstatic.com/iap/verify/public_key-jwk';
const IAP_ISSUER = 'https://cloud.google.com/iap';
const OAUTH2_ISSUER = 'accounts.google.com';
const OAUTH2_ISSUER_HTTPS = 'https://accounts.google.com';
const OAUTH2_REVOKE_URI = 'https://oauth2.googleapis.com/revoke';
/**
* @var callable
*/
private $httpHandler;
/**
* @var CacheItemPoolInterface
*/
private $cache;
/**
* @param callable $httpHandler [optional] An HTTP Handler to deliver PSR-7 requests.
* @param CacheItemPoolInterface $cache [optional] A PSR-6 compatible cache implementation.
*/
public function __construct(callable $httpHandler = null, \WPMailSMTP\Vendor\Psr\Cache\CacheItemPoolInterface $cache = null)
{
$this->httpHandler = $httpHandler ?: \WPMailSMTP\Vendor\Google\Auth\HttpHandler\HttpHandlerFactory::build(\WPMailSMTP\Vendor\Google\Auth\HttpHandler\HttpClientCache::getHttpClient());
$this->cache = $cache ?: new \WPMailSMTP\Vendor\Google\Auth\Cache\MemoryCacheItemPool();
}
/**
* Verifies an id token and returns the authenticated apiLoginTicket.
* Throws an exception if the id token is not valid.
* The audience parameter can be used to control which id tokens are
* accepted. By default, the id token must have been issued to this OAuth2 client.
*
* @param string $token The JSON Web Token to be verified.
* @param array $options [optional] Configuration options.
* @param string $options.audience The indended recipient of the token.
* @param string $options.issuer The intended issuer of the token.
* @param string $options.cacheKey The cache key of the cached certs. Defaults to
* the sha1 of $certsLocation if provided, otherwise is set to
* "federated_signon_certs_v3".
* @param string $options.certsLocation The location (remote or local) from which
* to retrieve certificates, if not cached. This value should only be
* provided in limited circumstances in which you are sure of the
* behavior.
* @param bool $options.throwException Whether the function should throw an
* exception if the verification fails. This is useful for
* determining the reason verification failed.
* @return array|bool the token payload, if successful, or false if not.
* @throws InvalidArgumentException If certs could not be retrieved from a local file.
* @throws InvalidArgumentException If received certs are in an invalid format.
* @throws InvalidArgumentException If the cert alg is not supported.
* @throws RuntimeException If certs could not be retrieved from a remote location.
* @throws UnexpectedValueException If the token issuer does not match.
* @throws UnexpectedValueException If the token audience does not match.
*/
public function verify($token, array $options = [])
{
$audience = isset($options['audience']) ? $options['audience'] : null;
$issuer = isset($options['issuer']) ? $options['issuer'] : null;
$certsLocation = isset($options['certsLocation']) ? $options['certsLocation'] : self::FEDERATED_SIGNON_CERT_URL;
$cacheKey = isset($options['cacheKey']) ? $options['cacheKey'] : $this->getCacheKeyFromCertLocation($certsLocation);
$throwException = isset($options['throwException']) ? $options['throwException'] : \false;
// for backwards compatibility
// Check signature against each available cert.
$certs = $this->getCerts($certsLocation, $cacheKey, $options);
$alg = $this->determineAlg($certs);
if (!\in_array($alg, ['RS256', 'ES256'])) {
throw new \InvalidArgumentException('unrecognized "alg" in certs, expected ES256 or RS256');
}
try {
if ($alg == 'RS256') {
return $this->verifyRs256($token, $certs, $audience, $issuer);
}
return $this->verifyEs256($token, $certs, $audience, $issuer);
} catch (\WPMailSMTP\Vendor\Firebase\JWT\ExpiredException $e) {
// firebase/php-jwt 3+
} catch (\WPMailSMTP\Vendor\ExpiredException $e) {
// firebase/php-jwt 2
} catch (\WPMailSMTP\Vendor\Firebase\JWT\SignatureInvalidException $e) {
// firebase/php-jwt 3+
} catch (\WPMailSMTP\Vendor\SignatureInvalidException $e) {
// firebase/php-jwt 2
} catch (\WPMailSMTP\Vendor\SimpleJWT\InvalidTokenException $e) {
// simplejwt
} catch (\WPMailSMTP\Vendor\Google\Auth\DomainException $e) {
} catch (\InvalidArgumentException $e) {
} catch (\UnexpectedValueException $e) {
}
if ($throwException) {
throw $e;
}
return \false;
}
/**
* Identifies the expected algorithm to verify by looking at the "alg" key
* of the provided certs.
*
* @param array $certs Certificate array according to the JWK spec (see
* https://tools.ietf.org/html/rfc7517).
* @return string The expected algorithm, such as "ES256" or "RS256".
*/
private function determineAlg(array $certs)
{
$alg = null;
foreach ($certs as $cert) {
if (empty($cert['alg'])) {
throw new \InvalidArgumentException('certs expects "alg" to be set');
}
$alg = $alg ?: $cert['alg'];
if ($alg != $cert['alg']) {
throw new \InvalidArgumentException('More than one alg detected in certs');
}
}
return $alg;
}
/**
* Verifies an ES256-signed JWT.
*
* @param string $token The JSON Web Token to be verified.
* @param array $certs Certificate array according to the JWK spec (see
* https://tools.ietf.org/html/rfc7517).
* @param string|null $audience If set, returns false if the provided
* audience does not match the "aud" claim on the JWT.
* @param string|null $issuer If set, returns false if the provided
* issuer does not match the "iss" claim on the JWT.
* @return array|bool the token payload, if successful, or false if not.
*/
private function verifyEs256($token, array $certs, $audience = null, $issuer = null)
{
$this->checkSimpleJwt();
$jwkset = new \WPMailSMTP\Vendor\SimpleJWT\Keys\KeySet();
foreach ($certs as $cert) {
$jwkset->add(\WPMailSMTP\Vendor\SimpleJWT\Keys\KeyFactory::create($cert, 'php'));
}
// Validate the signature using the key set and ES256 algorithm.
$jwt = $this->callSimpleJwtDecode([$token, $jwkset, 'ES256']);
$payload = $jwt->getClaims();
if (isset($payload['aud'])) {
if ($audience && $payload['aud'] != $audience) {
throw new \UnexpectedValueException('Audience does not match');
}
}
// @see https://cloud.google.com/iap/docs/signed-headers-howto#verifying_the_jwt_payload
$issuer = $issuer ?: self::IAP_ISSUER;
if (!isset($payload['iss']) || $payload['iss'] !== $issuer) {
throw new \UnexpectedValueException('Issuer does not match');
}
return $payload;
}
/**
* Verifies an RS256-signed JWT.
*
* @param string $token The JSON Web Token to be verified.
* @param array $certs Certificate array according to the JWK spec (see
* https://tools.ietf.org/html/rfc7517).
* @param string|null $audience If set, returns false if the provided
* audience does not match the "aud" claim on the JWT.
* @param string|null $issuer If set, returns false if the provided
* issuer does not match the "iss" claim on the JWT.
* @return array|bool the token payload, if successful, or false if not.
*/
private function verifyRs256($token, array $certs, $audience = null, $issuer = null)
{
$this->checkAndInitializePhpsec();
$keys = [];
foreach ($certs as $cert) {
if (empty($cert['kid'])) {
throw new \InvalidArgumentException('certs expects "kid" to be set');
}
if (empty($cert['n']) || empty($cert['e'])) {
throw new \InvalidArgumentException('RSA certs expects "n" and "e" to be set');
}
$rsa = new \WPMailSMTP\Vendor\phpseclib\Crypt\RSA();
$rsa->loadKey(['n' => new \WPMailSMTP\Vendor\phpseclib\Math\BigInteger($this->callJwtStatic('urlsafeB64Decode', [$cert['n']]), 256), 'e' => new \WPMailSMTP\Vendor\phpseclib\Math\BigInteger($this->callJwtStatic('urlsafeB64Decode', [$cert['e']]), 256)]);
// create an array of key IDs to certs for the JWT library
$keys[$cert['kid']] = $rsa->getPublicKey();
}
$payload = $this->callJwtStatic('decode', [$token, $keys, ['RS256']]);
if (\property_exists($payload, 'aud')) {
if ($audience && $payload->aud != $audience) {
throw new \UnexpectedValueException('Audience does not match');
}
}
// support HTTP and HTTPS issuers
// @see https://developers.google.com/identity/sign-in/web/backend-auth
$issuers = $issuer ? [$issuer] : [self::OAUTH2_ISSUER, self::OAUTH2_ISSUER_HTTPS];
if (!isset($payload->iss) || !\in_array($payload->iss, $issuers)) {
throw new \UnexpectedValueException('Issuer does not match');
}
return (array) $payload;
}
/**
* Revoke an OAuth2 access token or refresh token. This method will revoke the current access
* token, if a token isn't provided.
*
* @param string|array $token The token (access token or a refresh token) that should be revoked.
* @param array $options [optional] Configuration options.
* @return bool Returns True if the revocation was successful, otherwise False.
*/
public function revoke($token, array $options = [])
{
if (\is_array($token)) {
if (isset($token['refresh_token'])) {
$token = $token['refresh_token'];
} else {
$token = $token['access_token'];
}
}
$body = \WPMailSMTP\Vendor\GuzzleHttp\Psr7\stream_for(\http_build_query(['token' => $token]));
$request = new \WPMailSMTP\Vendor\GuzzleHttp\Psr7\Request('POST', self::OAUTH2_REVOKE_URI, ['Cache-Control' => 'no-store', 'Content-Type' => 'application/x-www-form-urlencoded'], $body);
$httpHandler = $this->httpHandler;
$response = $httpHandler($request, $options);
return $response->getStatusCode() == 200;
}
/**
* Gets federated sign-on certificates to use for verifying identity tokens.
* Returns certs as array structure, where keys are key ids, and values
* are PEM encoded certificates.
*
* @param string $location The location from which to retrieve certs.
* @param string $cacheKey The key under which to cache the retrieved certs.
* @param array $options [optional] Configuration options.
* @return array
* @throws InvalidArgumentException If received certs are in an invalid format.
*/
private function getCerts($location, $cacheKey, array $options = [])
{
$cacheItem = $this->cache->getItem($cacheKey);
$certs = $cacheItem ? $cacheItem->get() : null;
$gotNewCerts = \false;
if (!$certs) {
$certs = $this->retrieveCertsFromLocation($location, $options);
$gotNewCerts = \true;
}
if (!isset($certs['keys'])) {
if ($location !== self::IAP_CERT_URL) {
throw new \InvalidArgumentException('federated sign-on certs expects "keys" to be set');
}
throw new \InvalidArgumentException('certs expects "keys" to be set');
}
// Push caching off until after verifying certs are in a valid format.
// Don't want to cache bad data.
if ($gotNewCerts) {
$cacheItem->expiresAt(new \DateTime('+1 hour'));
$cacheItem->set($certs);
$this->cache->save($cacheItem);
}
return $certs['keys'];
}
/**
* Retrieve and cache a certificates file.
*
* @param $url string location
* @param array $options [optional] Configuration options.
* @return array certificates
* @throws InvalidArgumentException If certs could not be retrieved from a local file.
* @throws RuntimeException If certs could not be retrieved from a remote location.
*/
private function retrieveCertsFromLocation($url, array $options = [])
{
// If we're retrieving a local file, just grab it.
if (\strpos($url, 'http') !== 0) {
if (!\file_exists($url)) {
throw new \InvalidArgumentException(\sprintf('Failed to retrieve verification certificates from path: %s.', $url));
}
return \json_decode(\file_get_contents($url), \true);
}
$httpHandler = $this->httpHandler;
$response = $httpHandler(new \WPMailSMTP\Vendor\GuzzleHttp\Psr7\Request('GET', $url), $options);
if ($response->getStatusCode() == 200) {
return \json_decode((string) $response->getBody(), \true);
}
throw new \RuntimeException(\sprintf('Failed to retrieve verification certificates: "%s".', $response->getBody()->getContents()), $response->getStatusCode());
}
private function checkAndInitializePhpsec()
{
// @codeCoverageIgnoreStart
if (!\class_exists('WPMailSMTP\\Vendor\\phpseclib\\Crypt\\RSA')) {
throw new \RuntimeException('Please require phpseclib/phpseclib v2 to use this utility.');
}
// @codeCoverageIgnoreEnd
$this->setPhpsecConstants();
}
private function checkSimpleJwt()
{
// @codeCoverageIgnoreStart
if (!\class_exists('WPMailSMTP\\Vendor\\SimpleJWT\\JWT')) {
throw new \RuntimeException('Please require kelvinmo/simplejwt ^0.2 to use this utility.');
}
// @codeCoverageIgnoreEnd
}
/**
* phpseclib calls "phpinfo" by default, which requires special
* whitelisting in the AppEngine VM environment. This function
* sets constants to bypass the need for phpseclib to check phpinfo
*
* @see phpseclib/Math/BigInteger
* @see https://github.com/GoogleCloudPlatform/getting-started-php/issues/85
* @codeCoverageIgnore
*/
private function setPhpsecConstants()
{
if (\filter_var(\getenv('GAE_VM'), \FILTER_VALIDATE_BOOLEAN)) {
if (!\defined('WPMailSMTP\\Vendor\\MATH_BIGINTEGER_OPENSSL_ENABLED')) {
\define('WPMailSMTP\\Vendor\\MATH_BIGINTEGER_OPENSSL_ENABLED', \true);
}
if (!\defined('WPMailSMTP\\Vendor\\CRYPT_RSA_MODE')) {
\define('WPMailSMTP\\Vendor\\CRYPT_RSA_MODE', \WPMailSMTP\Vendor\phpseclib\Crypt\RSA::MODE_OPENSSL);
}
}
}
/**
* Provide a hook to mock calls to the JWT static methods.
*
* @param string $method
* @param array $args
* @return mixed
*/
protected function callJwtStatic($method, array $args = [])
{
$class = \class_exists('WPMailSMTP\\Vendor\\Firebase\\JWT\\JWT') ? 'Firebase\\JWT\\JWT' : 'JWT';
return \call_user_func_array([$class, $method], $args);
}
/**
* Provide a hook to mock calls to the JWT static methods.
*
* @param array $args
* @return mixed
*/
protected function callSimpleJwtDecode(array $args = [])
{
return \call_user_func_array(['SimpleJWT\\JWT', 'decode'], $args);
}
/**
* Generate a cache key based on the cert location using sha1 with the
* exception of using "federated_signon_certs_v3" to preserve BC.
*
* @param string $certsLocation
* @return string
*/
private function getCacheKeyFromCertLocation($certsLocation)
{
$key = $certsLocation === self::FEDERATED_SIGNON_CERT_URL ? 'federated_signon_certs_v3' : \sha1($certsLocation);
return 'google_auth_certs_cache|' . $key;
}
}

View File

@ -0,0 +1,249 @@
<?php
/*
* Copyright 2015 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.
*/
namespace WPMailSMTP\Vendor\Google\Auth;
use DomainException;
use WPMailSMTP\Vendor\Google\Auth\Credentials\AppIdentityCredentials;
use WPMailSMTP\Vendor\Google\Auth\Credentials\GCECredentials;
use WPMailSMTP\Vendor\Google\Auth\Credentials\ServiceAccountCredentials;
use WPMailSMTP\Vendor\Google\Auth\HttpHandler\HttpClientCache;
use WPMailSMTP\Vendor\Google\Auth\HttpHandler\HttpHandlerFactory;
use WPMailSMTP\Vendor\Google\Auth\Middleware\AuthTokenMiddleware;
use WPMailSMTP\Vendor\Google\Auth\Subscriber\AuthTokenSubscriber;
use WPMailSMTP\Vendor\GuzzleHttp\Client;
use InvalidArgumentException;
use WPMailSMTP\Vendor\Psr\Cache\CacheItemPoolInterface;
/**
* ApplicationDefaultCredentials obtains the default credentials for
* authorizing a request to a Google service.
*
* Application Default Credentials are described here:
* https://developers.google.com/accounts/docs/application-default-credentials
*
* This class implements the search for the application default credentials as
* described in the link.
*
* It provides three factory methods:
* - #get returns the computed credentials object
* - #getSubscriber returns an AuthTokenSubscriber built from the credentials object
* - #getMiddleware returns an AuthTokenMiddleware built from the credentials object
*
* This allows it to be used as follows with GuzzleHttp\Client:
*
* ```
* use Google\Auth\ApplicationDefaultCredentials;
* use GuzzleHttp\Client;
* use GuzzleHttp\HandlerStack;
*
* $middleware = ApplicationDefaultCredentials::getMiddleware(
* 'https://www.googleapis.com/auth/taskqueue'
* );
* $stack = HandlerStack::create();
* $stack->push($middleware);
*
* $client = new Client([
* 'handler' => $stack,
* 'base_uri' => 'https://www.googleapis.com/taskqueue/v1beta2/projects/',
* 'auth' => 'google_auth' // authorize all requests
* ]);
*
* $res = $client->get('myproject/taskqueues/myqueue');
* ```
*/
class ApplicationDefaultCredentials
{
/**
* Obtains an AuthTokenSubscriber that uses the default FetchAuthTokenInterface
* implementation to use in this environment.
*
* If supplied, $scope is used to in creating the credentials instance if
* this does not fallback to the compute engine defaults.
*
* @param string|array scope the scope of the access request, expressed
* either as an Array or as a space-delimited String.
* @param callable $httpHandler callback which delivers psr7 request
* @param array $cacheConfig configuration for the cache when it's present
* @param CacheItemPoolInterface $cache A cache implementation, may be
* provided if you have one already available for use.
* @return AuthTokenSubscriber
* @throws DomainException if no implementation can be obtained.
*/
public static function getSubscriber($scope = null, callable $httpHandler = null, array $cacheConfig = null, \WPMailSMTP\Vendor\Psr\Cache\CacheItemPoolInterface $cache = null)
{
$creds = self::getCredentials($scope, $httpHandler, $cacheConfig, $cache);
return new \WPMailSMTP\Vendor\Google\Auth\Subscriber\AuthTokenSubscriber($creds, $httpHandler);
}
/**
* Obtains an AuthTokenMiddleware that uses the default FetchAuthTokenInterface
* implementation to use in this environment.
*
* If supplied, $scope is used to in creating the credentials instance if
* this does not fallback to the compute engine defaults.
*
* @param string|array scope the scope of the access request, expressed
* either as an Array or as a space-delimited String.
* @param callable $httpHandler callback which delivers psr7 request
* @param array $cacheConfig configuration for the cache when it's present
* @param CacheItemPoolInterface $cache A cache implementation, may be
* provided if you have one already available for use.
* @param string $quotaProject specifies a project to bill for access
* charges associated with the request.
* @return AuthTokenMiddleware
* @throws DomainException if no implementation can be obtained.
*/
public static function getMiddleware($scope = null, callable $httpHandler = null, array $cacheConfig = null, \WPMailSMTP\Vendor\Psr\Cache\CacheItemPoolInterface $cache = null, $quotaProject = null)
{
$creds = self::getCredentials($scope, $httpHandler, $cacheConfig, $cache, $quotaProject);
return new \WPMailSMTP\Vendor\Google\Auth\Middleware\AuthTokenMiddleware($creds, $httpHandler);
}
/**
* Obtains an AuthTokenMiddleware which will fetch an access token to use in
* the Authorization header. The middleware is configured with the default
* FetchAuthTokenInterface implementation to use in this environment.
*
* If supplied, $scope is used to in creating the credentials instance if
* this does not fallback to the Compute Engine defaults.
*
* @param string|array scope the scope of the access request, expressed
* either as an Array or as a space-delimited String.
* @param callable $httpHandler callback which delivers psr7 request
* @param array $cacheConfig configuration for the cache when it's present
* @param CacheItemPoolInterface $cache A cache implementation, may be
* provided if you have one already available for use.
* @param string $quotaProject specifies a project to bill for access
* charges associated with the request.
*
* @return CredentialsLoader
* @throws DomainException if no implementation can be obtained.
*/
public static function getCredentials($scope = null, callable $httpHandler = null, array $cacheConfig = null, \WPMailSMTP\Vendor\Psr\Cache\CacheItemPoolInterface $cache = null, $quotaProject = null)
{
$creds = null;
$jsonKey = \WPMailSMTP\Vendor\Google\Auth\CredentialsLoader::fromEnv() ?: \WPMailSMTP\Vendor\Google\Auth\CredentialsLoader::fromWellKnownFile();
if (!$httpHandler) {
if (!($client = \WPMailSMTP\Vendor\Google\Auth\HttpHandler\HttpClientCache::getHttpClient())) {
$client = new \WPMailSMTP\Vendor\GuzzleHttp\Client();
\WPMailSMTP\Vendor\Google\Auth\HttpHandler\HttpClientCache::setHttpClient($client);
}
$httpHandler = \WPMailSMTP\Vendor\Google\Auth\HttpHandler\HttpHandlerFactory::build($client);
}
if (!\is_null($jsonKey)) {
if ($quotaProject) {
$jsonKey['quota_project_id'] = $quotaProject;
}
$creds = \WPMailSMTP\Vendor\Google\Auth\CredentialsLoader::makeCredentials($scope, $jsonKey);
} elseif (\WPMailSMTP\Vendor\Google\Auth\Credentials\AppIdentityCredentials::onAppEngine() && !\WPMailSMTP\Vendor\Google\Auth\Credentials\GCECredentials::onAppEngineFlexible()) {
$creds = new \WPMailSMTP\Vendor\Google\Auth\Credentials\AppIdentityCredentials($scope);
} elseif (self::onGce($httpHandler, $cacheConfig, $cache)) {
$creds = new \WPMailSMTP\Vendor\Google\Auth\Credentials\GCECredentials(null, $scope, null, $quotaProject);
}
if (\is_null($creds)) {
throw new \DomainException(self::notFound());
}
if (!\is_null($cache)) {
$creds = new \WPMailSMTP\Vendor\Google\Auth\FetchAuthTokenCache($creds, $cacheConfig, $cache);
}
return $creds;
}
/**
* Obtains an AuthTokenMiddleware which will fetch an ID token to use in the
* Authorization header. The middleware is configured with the default
* FetchAuthTokenInterface implementation to use in this environment.
*
* If supplied, $targetAudience is used to set the "aud" on the resulting
* ID token.
*
* @param string $targetAudience The audience for the ID token.
* @param callable $httpHandler callback which delivers psr7 request
* @param array $cacheConfig configuration for the cache when it's present
* @param CacheItemPoolInterface $cache A cache implementation, may be
* provided if you have one already available for use.
* @return AuthTokenMiddleware
* @throws DomainException if no implementation can be obtained.
*/
public static function getIdTokenMiddleware($targetAudience, callable $httpHandler = null, array $cacheConfig = null, \WPMailSMTP\Vendor\Psr\Cache\CacheItemPoolInterface $cache = null)
{
$creds = self::getIdTokenCredentials($targetAudience, $httpHandler, $cacheConfig, $cache);
return new \WPMailSMTP\Vendor\Google\Auth\Middleware\AuthTokenMiddleware($creds, $httpHandler);
}
/**
* Obtains the default FetchAuthTokenInterface implementation to use
* in this environment, configured with a $targetAudience for fetching an ID
* token.
*
* @param string $targetAudience The audience for the ID token.
* @param callable $httpHandler callback which delivers psr7 request
* @param array $cacheConfig configuration for the cache when it's present
* @param CacheItemPoolInterface $cache A cache implementation, may be
* provided if you have one already available for use.
* @return CredentialsLoader
* @throws DomainException if no implementation can be obtained.
* @throws InvalidArgumentException if JSON "type" key is invalid
*/
public static function getIdTokenCredentials($targetAudience, callable $httpHandler = null, array $cacheConfig = null, \WPMailSMTP\Vendor\Psr\Cache\CacheItemPoolInterface $cache = null)
{
$creds = null;
$jsonKey = \WPMailSMTP\Vendor\Google\Auth\CredentialsLoader::fromEnv() ?: \WPMailSMTP\Vendor\Google\Auth\CredentialsLoader::fromWellKnownFile();
if (!$httpHandler) {
if (!($client = \WPMailSMTP\Vendor\Google\Auth\HttpHandler\HttpClientCache::getHttpClient())) {
$client = new \WPMailSMTP\Vendor\GuzzleHttp\Client();
\WPMailSMTP\Vendor\Google\Auth\HttpHandler\HttpClientCache::setHttpClient($client);
}
$httpHandler = \WPMailSMTP\Vendor\Google\Auth\HttpHandler\HttpHandlerFactory::build($client);
}
if (!\is_null($jsonKey)) {
if (!\array_key_exists('type', $jsonKey)) {
throw new \InvalidArgumentException('json key is missing the type field');
}
if ($jsonKey['type'] == 'authorized_user') {
throw new \InvalidArgumentException('ID tokens are not supported for end user credentials');
}
if ($jsonKey['type'] != 'service_account') {
throw new \InvalidArgumentException('invalid value in the type field');
}
$creds = new \WPMailSMTP\Vendor\Google\Auth\Credentials\ServiceAccountCredentials(null, $jsonKey, null, $targetAudience);
} elseif (self::onGce($httpHandler, $cacheConfig, $cache)) {
$creds = new \WPMailSMTP\Vendor\Google\Auth\Credentials\GCECredentials(null, null, $targetAudience);
}
if (\is_null($creds)) {
throw new \DomainException(self::notFound());
}
if (!\is_null($cache)) {
$creds = new \WPMailSMTP\Vendor\Google\Auth\FetchAuthTokenCache($creds, $cacheConfig, $cache);
}
return $creds;
}
private static function notFound()
{
$msg = 'Could not load the default credentials. Browse to ';
$msg .= 'https://developers.google.com';
$msg .= '/accounts/docs/application-default-credentials';
$msg .= ' for more information';
return $msg;
}
private static function onGce(callable $httpHandler = null, array $cacheConfig = null, \WPMailSMTP\Vendor\Psr\Cache\CacheItemPoolInterface $cache = null)
{
$gceCacheConfig = [];
foreach (['lifetime', 'prefix'] as $key) {
if (isset($cacheConfig['gce_' . $key])) {
$gceCacheConfig[$key] = $cacheConfig['gce_' . $key];
}
}
return (new \WPMailSMTP\Vendor\Google\Auth\GCECache($gceCacheConfig, $cache))->onGce($httpHandler);
}
}

View File

@ -0,0 +1,23 @@
<?php
/*
* Copyright 2016 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.
*/
namespace WPMailSMTP\Vendor\Google\Auth\Cache;
use WPMailSMTP\Vendor\Psr\Cache\InvalidArgumentException as PsrInvalidArgumentException;
class InvalidArgumentException extends \InvalidArgumentException implements \WPMailSMTP\Vendor\Psr\Cache\InvalidArgumentException
{
}

View File

@ -0,0 +1,155 @@
<?php
/*
* Copyright 2016 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.
*/
namespace WPMailSMTP\Vendor\Google\Auth\Cache;
use WPMailSMTP\Vendor\Psr\Cache\CacheItemInterface;
/**
* A cache item.
*/
final class Item implements \WPMailSMTP\Vendor\Psr\Cache\CacheItemInterface
{
/**
* @var string
*/
private $key;
/**
* @var mixed
*/
private $value;
/**
* @var \DateTime|null
*/
private $expiration;
/**
* @var bool
*/
private $isHit = \false;
/**
* @param string $key
*/
public function __construct($key)
{
$this->key = $key;
}
/**
* {@inheritdoc}
*/
public function getKey()
{
return $this->key;
}
/**
* {@inheritdoc}
*/
public function get()
{
return $this->isHit() ? $this->value : null;
}
/**
* {@inheritdoc}
*/
public function isHit()
{
if (!$this->isHit) {
return \false;
}
if ($this->expiration === null) {
return \true;
}
return $this->currentTime()->getTimestamp() < $this->expiration->getTimestamp();
}
/**
* {@inheritdoc}
*/
public function set($value)
{
$this->isHit = \true;
$this->value = $value;
return $this;
}
/**
* {@inheritdoc}
*/
public function expiresAt($expiration)
{
if ($this->isValidExpiration($expiration)) {
$this->expiration = $expiration;
return $this;
}
$implementationMessage = \interface_exists('DateTimeInterface') ? 'implement interface DateTimeInterface' : 'be an instance of DateTime';
$error = \sprintf('Argument 1 passed to %s::expiresAt() must %s, %s given', \get_class($this), $implementationMessage, \gettype($expiration));
$this->handleError($error);
}
/**
* {@inheritdoc}
*/
public function expiresAfter($time)
{
if (\is_int($time)) {
$this->expiration = $this->currentTime()->add(new \DateInterval("PT{$time}S"));
} elseif ($time instanceof \DateInterval) {
$this->expiration = $this->currentTime()->add($time);
} elseif ($time === null) {
$this->expiration = $time;
} else {
$message = 'Argument 1 passed to %s::expiresAfter() must be an ' . 'instance of DateInterval or of the type integer, %s given';
$error = \sprintf($message, \get_class($this), \gettype($time));
$this->handleError($error);
}
return $this;
}
/**
* Handles an error.
*
* @param string $error
* @throws \TypeError
*/
private function handleError($error)
{
if (\class_exists('TypeError')) {
throw new \TypeError($error);
}
\trigger_error($error, \E_USER_ERROR);
}
/**
* Determines if an expiration is valid based on the rules defined by PSR6.
*
* @param mixed $expiration
* @return bool
*/
private function isValidExpiration($expiration)
{
if ($expiration === null) {
return \true;
}
// We test for two types here due to the fact the DateTimeInterface
// was not introduced until PHP 5.5. Checking for the DateTime type as
// well allows us to support 5.4.
if ($expiration instanceof \DateTimeInterface) {
return \true;
}
if ($expiration instanceof \DateTime) {
return \true;
}
return \false;
}
protected function currentTime()
{
return new \DateTime('now', new \DateTimeZone('UTC'));
}
}

View File

@ -0,0 +1,130 @@
<?php
/*
* Copyright 2016 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.
*/
namespace WPMailSMTP\Vendor\Google\Auth\Cache;
use WPMailSMTP\Vendor\Psr\Cache\CacheItemInterface;
use WPMailSMTP\Vendor\Psr\Cache\CacheItemPoolInterface;
/**
* Simple in-memory cache implementation.
*/
final class MemoryCacheItemPool implements \WPMailSMTP\Vendor\Psr\Cache\CacheItemPoolInterface
{
/**
* @var CacheItemInterface[]
*/
private $items;
/**
* @var CacheItemInterface[]
*/
private $deferredItems;
/**
* {@inheritdoc}
*/
public function getItem($key)
{
return \current($this->getItems([$key]));
}
/**
* {@inheritdoc}
*/
public function getItems(array $keys = [])
{
$items = [];
foreach ($keys as $key) {
$items[$key] = $this->hasItem($key) ? clone $this->items[$key] : new \WPMailSMTP\Vendor\Google\Auth\Cache\Item($key);
}
return $items;
}
/**
* {@inheritdoc}
*/
public function hasItem($key)
{
$this->isValidKey($key);
return isset($this->items[$key]) && $this->items[$key]->isHit();
}
/**
* {@inheritdoc}
*/
public function clear()
{
$this->items = [];
$this->deferredItems = [];
return \true;
}
/**
* {@inheritdoc}
*/
public function deleteItem($key)
{
return $this->deleteItems([$key]);
}
/**
* {@inheritdoc}
*/
public function deleteItems(array $keys)
{
\array_walk($keys, [$this, 'isValidKey']);
foreach ($keys as $key) {
unset($this->items[$key]);
}
return \true;
}
/**
* {@inheritdoc}
*/
public function save(\WPMailSMTP\Vendor\Psr\Cache\CacheItemInterface $item)
{
$this->items[$item->getKey()] = $item;
return \true;
}
/**
* {@inheritdoc}
*/
public function saveDeferred(\WPMailSMTP\Vendor\Psr\Cache\CacheItemInterface $item)
{
$this->deferredItems[$item->getKey()] = $item;
return \true;
}
/**
* {@inheritdoc}
*/
public function commit()
{
foreach ($this->deferredItems as $item) {
$this->save($item);
}
$this->deferredItems = [];
return \true;
}
/**
* Determines if the provided key is valid.
*
* @param string $key
* @return bool
* @throws InvalidArgumentException
*/
private function isValidKey($key)
{
$invalidCharacters = '{}()/\\\\@:';
if (!\is_string($key) || \preg_match("#[{$invalidCharacters}]#", $key)) {
throw new \WPMailSMTP\Vendor\Google\Auth\Cache\InvalidArgumentException('The provided key is not valid: ' . \var_export($key, \true));
}
return \true;
}
}

View File

@ -0,0 +1,198 @@
<?php
/**
* Copyright 2018 Google Inc. All Rights Reserved.
*
* 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.
*/
namespace WPMailSMTP\Vendor\Google\Auth\Cache;
use WPMailSMTP\Vendor\Psr\Cache\CacheItemInterface;
use WPMailSMTP\Vendor\Psr\Cache\CacheItemPoolInterface;
/**
* SystemV shared memory based CacheItemPool implementation.
*
* This CacheItemPool implementation can be used among multiple processes, but
* it doesn't provide any locking mechanism. If multiple processes write to
* this ItemPool, you have to avoid race condition manually in your code.
*/
class SysVCacheItemPool implements \WPMailSMTP\Vendor\Psr\Cache\CacheItemPoolInterface
{
const VAR_KEY = 1;
const DEFAULT_PROJ = 'A';
const DEFAULT_MEMSIZE = 10000;
const DEFAULT_PERM = 0600;
/** @var int */
private $sysvKey;
/**
* @var CacheItemInterface[]
*/
private $items;
/**
* @var CacheItemInterface[]
*/
private $deferredItems;
/**
* @var array
*/
private $options;
/*
* @var bool
*/
private $hasLoadedItems = \false;
/**
* Create a SystemV shared memory based CacheItemPool.
*
* @param array $options [optional] Configuration options.
* @param int $options.variableKey The variable key for getting the data from
* the shared memory. **Defaults to** 1.
* @param $options.proj string The project identifier for ftok. This needs to
* be a one character string. **Defaults to** 'A'.
* @param $options.memsize int The memory size in bytes for shm_attach.
* **Defaults to** 10000.
* @param $options.perm int The permission for shm_attach. **Defaults to**
* 0600.
*/
public function __construct($options = [])
{
if (!\extension_loaded('sysvshm')) {
throw new \RuntimeException('sysvshm extension is required to use this ItemPool');
}
$this->options = $options + ['variableKey' => self::VAR_KEY, 'proj' => self::DEFAULT_PROJ, 'memsize' => self::DEFAULT_MEMSIZE, 'perm' => self::DEFAULT_PERM];
$this->items = [];
$this->deferredItems = [];
$this->sysvKey = \ftok(__FILE__, $this->options['proj']);
}
public function getItem($key)
{
$this->loadItems();
return \current($this->getItems([$key]));
}
/**
* {@inheritdoc}
*/
public function getItems(array $keys = [])
{
$this->loadItems();
$items = [];
foreach ($keys as $key) {
$items[$key] = $this->hasItem($key) ? clone $this->items[$key] : new \WPMailSMTP\Vendor\Google\Auth\Cache\Item($key);
}
return $items;
}
/**
* {@inheritdoc}
*/
public function hasItem($key)
{
$this->loadItems();
return isset($this->items[$key]) && $this->items[$key]->isHit();
}
/**
* {@inheritdoc}
*/
public function clear()
{
$this->items = [];
$this->deferredItems = [];
return $this->saveCurrentItems();
}
/**
* {@inheritdoc}
*/
public function deleteItem($key)
{
return $this->deleteItems([$key]);
}
/**
* {@inheritdoc}
*/
public function deleteItems(array $keys)
{
if (!$this->hasLoadedItems) {
$this->loadItems();
}
foreach ($keys as $key) {
unset($this->items[$key]);
}
return $this->saveCurrentItems();
}
/**
* {@inheritdoc}
*/
public function save(\WPMailSMTP\Vendor\Psr\Cache\CacheItemInterface $item)
{
if (!$this->hasLoadedItems) {
$this->loadItems();
}
$this->items[$item->getKey()] = $item;
return $this->saveCurrentItems();
}
/**
* {@inheritdoc}
*/
public function saveDeferred(\WPMailSMTP\Vendor\Psr\Cache\CacheItemInterface $item)
{
$this->deferredItems[$item->getKey()] = $item;
return \true;
}
/**
* {@inheritdoc}
*/
public function commit()
{
foreach ($this->deferredItems as $item) {
if ($this->save($item) === \false) {
return \false;
}
}
$this->deferredItems = [];
return \true;
}
/**
* Save the current items.
*
* @return bool true when success, false upon failure
*/
private function saveCurrentItems()
{
$shmid = \shm_attach($this->sysvKey, $this->options['memsize'], $this->options['perm']);
if ($shmid !== \false) {
$ret = \shm_put_var($shmid, $this->options['variableKey'], $this->items);
\shm_detach($shmid);
return $ret;
}
return \false;
}
/**
* Load the items from the shared memory.
*
* @return bool true when success, false upon failure
*/
private function loadItems()
{
$shmid = \shm_attach($this->sysvKey, $this->options['memsize'], $this->options['perm']);
if ($shmid !== \false) {
$data = @\shm_get_var($shmid, $this->options['variableKey']);
if (!empty($data)) {
$this->items = $data;
} else {
$this->items = [];
}
\shm_detach($shmid);
$this->hasLoadedItems = \true;
return \true;
}
return \false;
}
}

View File

@ -0,0 +1,72 @@
<?php
/*
* Copyright 2015 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.
*/
namespace WPMailSMTP\Vendor\Google\Auth;
trait CacheTrait
{
private $maxKeyLength = 64;
/**
* Gets the cached value if it is present in the cache when that is
* available.
*/
private function getCachedValue($k)
{
if (\is_null($this->cache)) {
return;
}
$key = $this->getFullCacheKey($k);
if (\is_null($key)) {
return;
}
$cacheItem = $this->cache->getItem($key);
if ($cacheItem->isHit()) {
return $cacheItem->get();
}
}
/**
* Saves the value in the cache when that is available.
*/
private function setCachedValue($k, $v)
{
if (\is_null($this->cache)) {
return;
}
$key = $this->getFullCacheKey($k);
if (\is_null($key)) {
return;
}
$cacheItem = $this->cache->getItem($key);
$cacheItem->set($v);
$cacheItem->expiresAfter($this->cacheConfig['lifetime']);
return $this->cache->save($cacheItem);
}
private function getFullCacheKey($key)
{
if (\is_null($key)) {
return;
}
$key = $this->cacheConfig['prefix'] . $key;
// ensure we do not have illegal characters
$key = \preg_replace('|[^a-zA-Z0-9_\\.!]|', '', $key);
// Hash keys if they exceed $maxKeyLength (defaults to 64)
if ($this->maxKeyLength && \strlen($key) > $this->maxKeyLength) {
$key = \substr(\hash('sha256', $key), 0, $this->maxKeyLength);
}
return $key;
}
}

View File

@ -0,0 +1,200 @@
<?php
/*
* Copyright 2015 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.
*/
namespace WPMailSMTP\Vendor\Google\Auth\Credentials;
/*
* The AppIdentityService class is automatically defined on App Engine,
* so including this dependency is not necessary, and will result in a
* PHP fatal error in the App Engine environment.
*/
use WPMailSMTP\Vendor\google\appengine\api\app_identity\AppIdentityService;
use WPMailSMTP\Vendor\Google\Auth\CredentialsLoader;
use WPMailSMTP\Vendor\Google\Auth\ProjectIdProviderInterface;
use WPMailSMTP\Vendor\Google\Auth\SignBlobInterface;
/**
* AppIdentityCredentials supports authorization on Google App Engine.
*
* It can be used to authorize requests using the AuthTokenMiddleware or
* AuthTokenSubscriber, but will only succeed if being run on App Engine:
*
* Example:
* ```
* use Google\Auth\Credentials\AppIdentityCredentials;
* use Google\Auth\Middleware\AuthTokenMiddleware;
* use GuzzleHttp\Client;
* use GuzzleHttp\HandlerStack;
*
* $gae = new AppIdentityCredentials('https://www.googleapis.com/auth/books');
* $middleware = new AuthTokenMiddleware($gae);
* $stack = HandlerStack::create();
* $stack->push($middleware);
*
* $client = new Client([
* 'handler' => $stack,
* 'base_uri' => 'https://www.googleapis.com/books/v1',
* 'auth' => 'google_auth'
* ]);
*
* $res = $client->get('volumes?q=Henry+David+Thoreau&country=US');
* ```
*/
class AppIdentityCredentials extends \WPMailSMTP\Vendor\Google\Auth\CredentialsLoader implements \WPMailSMTP\Vendor\Google\Auth\SignBlobInterface, \WPMailSMTP\Vendor\Google\Auth\ProjectIdProviderInterface
{
/**
* Result of fetchAuthToken.
*
* @var array
*/
protected $lastReceivedToken;
/**
* Array of OAuth2 scopes to be requested.
*
* @var array
*/
private $scope;
/**
* @var string
*/
private $clientName;
/**
* @param array $scope One or more scopes.
*/
public function __construct($scope = array())
{
$this->scope = $scope;
}
/**
* Determines if this an App Engine instance, by accessing the
* SERVER_SOFTWARE environment variable (prod) or the APPENGINE_RUNTIME
* environment variable (dev).
*
* @return bool true if this an App Engine Instance, false otherwise
*/
public static function onAppEngine()
{
$appEngineProduction = isset($_SERVER['SERVER_SOFTWARE']) && 0 === \strpos($_SERVER['SERVER_SOFTWARE'], 'Google App Engine');
if ($appEngineProduction) {
return \true;
}
$appEngineDevAppServer = isset($_SERVER['APPENGINE_RUNTIME']) && $_SERVER['APPENGINE_RUNTIME'] == 'php';
if ($appEngineDevAppServer) {
return \true;
}
return \false;
}
/**
* Implements FetchAuthTokenInterface#fetchAuthToken.
*
* Fetches the auth tokens using the AppIdentityService if available.
* As the AppIdentityService uses protobufs to fetch the access token,
* the GuzzleHttp\ClientInterface instance passed in will not be used.
*
* @param callable $httpHandler callback which delivers psr7 request
* @return array A set of auth related metadata, containing the following
* keys:
* - access_token (string)
* - expiration_time (string)
*/
public function fetchAuthToken(callable $httpHandler = null)
{
try {
$this->checkAppEngineContext();
} catch (\Exception $e) {
return [];
}
// AppIdentityService expects an array when multiple scopes are supplied
$scope = \is_array($this->scope) ? $this->scope : \explode(' ', $this->scope);
$token = \WPMailSMTP\Vendor\google\appengine\api\app_identity\AppIdentityService::getAccessToken($scope);
$this->lastReceivedToken = $token;
return $token;
}
/**
* Sign a string using AppIdentityService.
*
* @param string $stringToSign The string to sign.
* @param bool $forceOpenSsl [optional] Does not apply to this credentials
* type.
* @return string The signature, base64-encoded.
* @throws \Exception If AppEngine SDK or mock is not available.
*/
public function signBlob($stringToSign, $forceOpenSsl = \false)
{
$this->checkAppEngineContext();
return \base64_encode(\WPMailSMTP\Vendor\google\appengine\api\app_identity\AppIdentityService::signForApp($stringToSign)['signature']);
}
/**
* Get the project ID from AppIdentityService.
*
* Returns null if AppIdentityService is unavailable.
*
* @param callable $httpHandler Not used by this type.
* @return string|null
*/
public function getProjectId(callable $httpHander = null)
{
try {
$this->checkAppEngineContext();
} catch (\Exception $e) {
return null;
}
return \WPMailSMTP\Vendor\google\appengine\api\app_identity\AppIdentityService::getApplicationId();
}
/**
* Get the client name from AppIdentityService.
*
* Subsequent calls to this method will return a cached value.
*
* @param callable $httpHandler Not used in this implementation.
* @return string
* @throws \Exception If AppEngine SDK or mock is not available.
*/
public function getClientName(callable $httpHandler = null)
{
$this->checkAppEngineContext();
if (!$this->clientName) {
$this->clientName = \WPMailSMTP\Vendor\google\appengine\api\app_identity\AppIdentityService::getServiceAccountName();
}
return $this->clientName;
}
/**
* @return array|null
*/
public function getLastReceivedToken()
{
if ($this->lastReceivedToken) {
return ['access_token' => $this->lastReceivedToken['access_token'], 'expires_at' => $this->lastReceivedToken['expiration_time']];
}
return null;
}
/**
* Caching is handled by the underlying AppIdentityService, return empty string
* to prevent caching.
*
* @return string
*/
public function getCacheKey()
{
return '';
}
private function checkAppEngineContext()
{
if (!self::onAppEngine() || !\class_exists('WPMailSMTP\\Vendor\\google\\appengine\\api\\app_identity\\AppIdentityService')) {
throw new \Exception('This class must be run in App Engine, or you must include the AppIdentityService ' . 'mock class defined in tests/mocks/AppIdentityService.php');
}
}
}

View File

@ -0,0 +1,392 @@
<?php
/*
* Copyright 2015 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.
*/
namespace WPMailSMTP\Vendor\Google\Auth\Credentials;
use WPMailSMTP\Vendor\Google\Auth\CredentialsLoader;
use WPMailSMTP\Vendor\Google\Auth\GetQuotaProjectInterface;
use WPMailSMTP\Vendor\Google\Auth\HttpHandler\HttpClientCache;
use WPMailSMTP\Vendor\Google\Auth\HttpHandler\HttpHandlerFactory;
use WPMailSMTP\Vendor\Google\Auth\Iam;
use WPMailSMTP\Vendor\Google\Auth\ProjectIdProviderInterface;
use WPMailSMTP\Vendor\Google\Auth\SignBlobInterface;
use WPMailSMTP\Vendor\GuzzleHttp\Exception\ClientException;
use WPMailSMTP\Vendor\GuzzleHttp\Exception\ConnectException;
use WPMailSMTP\Vendor\GuzzleHttp\Exception\RequestException;
use WPMailSMTP\Vendor\GuzzleHttp\Exception\ServerException;
use WPMailSMTP\Vendor\GuzzleHttp\Psr7\Request;
use InvalidArgumentException;
/**
* GCECredentials supports authorization on Google Compute Engine.
*
* It can be used to authorize requests using the AuthTokenMiddleware, but will
* only succeed if being run on GCE:
*
* use Google\Auth\Credentials\GCECredentials;
* use Google\Auth\Middleware\AuthTokenMiddleware;
* use GuzzleHttp\Client;
* use GuzzleHttp\HandlerStack;
*
* $gce = new GCECredentials();
* $middleware = new AuthTokenMiddleware($gce);
* $stack = HandlerStack::create();
* $stack->push($middleware);
*
* $client = new Client([
* 'handler' => $stack,
* 'base_uri' => 'https://www.googleapis.com/taskqueue/v1beta2/projects/',
* 'auth' => 'google_auth'
* ]);
*
* $res = $client->get('myproject/taskqueues/myqueue');
*/
class GCECredentials extends \WPMailSMTP\Vendor\Google\Auth\CredentialsLoader implements \WPMailSMTP\Vendor\Google\Auth\SignBlobInterface, \WPMailSMTP\Vendor\Google\Auth\ProjectIdProviderInterface, \WPMailSMTP\Vendor\Google\Auth\GetQuotaProjectInterface
{
// phpcs:disable
const cacheKey = 'GOOGLE_AUTH_PHP_GCE';
// phpcs:enable
/**
* The metadata IP address on appengine instances.
*
* The IP is used instead of the domain 'metadata' to avoid slow responses
* when not on Compute Engine.
*/
const METADATA_IP = '169.254.169.254';
/**
* The metadata path of the default token.
*/
const TOKEN_URI_PATH = 'v1/instance/service-accounts/default/token';
/**
* The metadata path of the default id token.
*/
const ID_TOKEN_URI_PATH = 'v1/instance/service-accounts/default/identity';
/**
* The metadata path of the client ID.
*/
const CLIENT_ID_URI_PATH = 'v1/instance/service-accounts/default/email';
/**
* The metadata path of the project ID.
*/
const PROJECT_ID_URI_PATH = 'v1/project/project-id';
/**
* The header whose presence indicates GCE presence.
*/
const FLAVOR_HEADER = 'Metadata-Flavor';
/**
* Note: the explicit `timeout` and `tries` below is a workaround. The underlying
* issue is that resolving an unknown host on some networks will take
* 20-30 seconds; making this timeout short fixes the issue, but
* could lead to false negatives in the event that we are on GCE, but
* the metadata resolution was particularly slow. The latter case is
* "unlikely" since the expected 4-nines time is about 0.5 seconds.
* This allows us to limit the total ping maximum timeout to 1.5 seconds
* for developer desktop scenarios.
*/
const MAX_COMPUTE_PING_TRIES = 3;
const COMPUTE_PING_CONNECTION_TIMEOUT_S = 0.5;
/**
* Flag used to ensure that the onGCE test is only done once;.
*
* @var bool
*/
private $hasCheckedOnGce = \false;
/**
* Flag that stores the value of the onGCE check.
*
* @var bool
*/
private $isOnGce = \false;
/**
* Result of fetchAuthToken.
*/
protected $lastReceivedToken;
/**
* @var string|null
*/
private $clientName;
/**
* @var string|null
*/
private $projectId;
/**
* @var Iam|null
*/
private $iam;
/**
* @var string
*/
private $tokenUri;
/**
* @var string
*/
private $targetAudience;
/**
* @var string|null
*/
private $quotaProject;
/**
* @param Iam $iam [optional] An IAM instance.
* @param string|array $scope [optional] the scope of the access request,
* expressed either as an array or as a space-delimited string.
* @param string $targetAudience [optional] The audience for the ID token.
* @param string $quotaProject [optional] Specifies a project to bill for access
* charges associated with the request.
*/
public function __construct(\WPMailSMTP\Vendor\Google\Auth\Iam $iam = null, $scope = null, $targetAudience = null, $quotaProject = null)
{
$this->iam = $iam;
if ($scope && $targetAudience) {
throw new \InvalidArgumentException('Scope and targetAudience cannot both be supplied');
}
$tokenUri = self::getTokenUri();
if ($scope) {
if (\is_string($scope)) {
$scope = \explode(' ', $scope);
}
$scope = \implode(',', $scope);
$tokenUri = $tokenUri . '?scopes=' . $scope;
} elseif ($targetAudience) {
$tokenUri = \sprintf('http://%s/computeMetadata/%s?audience=%s', self::METADATA_IP, self::ID_TOKEN_URI_PATH, $targetAudience);
$this->targetAudience = $targetAudience;
}
$this->tokenUri = $tokenUri;
$this->quotaProject = $quotaProject;
}
/**
* The full uri for accessing the default token.
*
* @return string
*/
public static function getTokenUri()
{
$base = 'http://' . self::METADATA_IP . '/computeMetadata/';
return $base . self::TOKEN_URI_PATH;
}
/**
* The full uri for accessing the default service account.
*
* @return string
*/
public static function getClientNameUri()
{
$base = 'http://' . self::METADATA_IP . '/computeMetadata/';
return $base . self::CLIENT_ID_URI_PATH;
}
/**
* The full uri for accessing the default project ID.
*
* @return string
*/
private static function getProjectIdUri()
{
$base = 'http://' . self::METADATA_IP . '/computeMetadata/';
return $base . self::PROJECT_ID_URI_PATH;
}
/**
* Determines if this an App Engine Flexible instance, by accessing the
* GAE_INSTANCE environment variable.
*
* @return bool true if this an App Engine Flexible Instance, false otherwise
*/
public static function onAppEngineFlexible()
{
return \substr(\getenv('GAE_INSTANCE'), 0, 4) === 'aef-';
}
/**
* Determines if this a GCE instance, by accessing the expected metadata
* host.
* If $httpHandler is not specified a the default HttpHandler is used.
*
* @param callable $httpHandler callback which delivers psr7 request
* @return bool True if this a GCEInstance, false otherwise
*/
public static function onGce(callable $httpHandler = null)
{
$httpHandler = $httpHandler ?: \WPMailSMTP\Vendor\Google\Auth\HttpHandler\HttpHandlerFactory::build(\WPMailSMTP\Vendor\Google\Auth\HttpHandler\HttpClientCache::getHttpClient());
$checkUri = 'http://' . self::METADATA_IP;
for ($i = 1; $i <= self::MAX_COMPUTE_PING_TRIES; $i++) {
try {
// Comment from: oauth2client/client.py
//
// Note: the explicit `timeout` below is a workaround. The underlying
// issue is that resolving an unknown host on some networks will take
// 20-30 seconds; making this timeout short fixes the issue, but
// could lead to false negatives in the event that we are on GCE, but
// the metadata resolution was particularly slow. The latter case is
// "unlikely".
$resp = $httpHandler(new \WPMailSMTP\Vendor\GuzzleHttp\Psr7\Request('GET', $checkUri, [self::FLAVOR_HEADER => 'Google']), ['timeout' => self::COMPUTE_PING_CONNECTION_TIMEOUT_S]);
return $resp->getHeaderLine(self::FLAVOR_HEADER) == 'Google';
} catch (\WPMailSMTP\Vendor\GuzzleHttp\Exception\ClientException $e) {
} catch (\WPMailSMTP\Vendor\GuzzleHttp\Exception\ServerException $e) {
} catch (\WPMailSMTP\Vendor\GuzzleHttp\Exception\RequestException $e) {
} catch (\WPMailSMTP\Vendor\GuzzleHttp\Exception\ConnectException $e) {
}
}
return \false;
}
/**
* Implements FetchAuthTokenInterface#fetchAuthToken.
*
* Fetches the auth tokens from the GCE metadata host if it is available.
* If $httpHandler is not specified a the default HttpHandler is used.
*
* @param callable $httpHandler callback which delivers psr7 request
*
* @return array A set of auth related metadata, based on the token type.
*
* Access tokens have the following keys:
* - access_token (string)
* - expires_in (int)
* - token_type (string)
* ID tokens have the following keys:
* - id_token (string)
*
* @throws \Exception
*/
public function fetchAuthToken(callable $httpHandler = null)
{
$httpHandler = $httpHandler ?: \WPMailSMTP\Vendor\Google\Auth\HttpHandler\HttpHandlerFactory::build(\WPMailSMTP\Vendor\Google\Auth\HttpHandler\HttpClientCache::getHttpClient());
if (!$this->hasCheckedOnGce) {
$this->isOnGce = self::onGce($httpHandler);
$this->hasCheckedOnGce = \true;
}
if (!$this->isOnGce) {
return array();
// return an empty array with no access token
}
$response = $this->getFromMetadata($httpHandler, $this->tokenUri);
if ($this->targetAudience) {
return ['id_token' => $response];
}
if (null === ($json = \json_decode($response, \true))) {
throw new \Exception('Invalid JSON response');
}
// store this so we can retrieve it later
$this->lastReceivedToken = $json;
$this->lastReceivedToken['expires_at'] = \time() + $json['expires_in'];
return $json;
}
/**
* @return string
*/
public function getCacheKey()
{
return self::cacheKey;
}
/**
* @return array|null
*/
public function getLastReceivedToken()
{
if ($this->lastReceivedToken) {
return ['access_token' => $this->lastReceivedToken['access_token'], 'expires_at' => $this->lastReceivedToken['expires_at']];
}
return null;
}
/**
* Get the client name from GCE metadata.
*
* Subsequent calls will return a cached value.
*
* @param callable $httpHandler callback which delivers psr7 request
* @return string
*/
public function getClientName(callable $httpHandler = null)
{
if ($this->clientName) {
return $this->clientName;
}
$httpHandler = $httpHandler ?: \WPMailSMTP\Vendor\Google\Auth\HttpHandler\HttpHandlerFactory::build(\WPMailSMTP\Vendor\Google\Auth\HttpHandler\HttpClientCache::getHttpClient());
if (!$this->hasCheckedOnGce) {
$this->isOnGce = self::onGce($httpHandler);
$this->hasCheckedOnGce = \true;
}
if (!$this->isOnGce) {
return '';
}
$this->clientName = $this->getFromMetadata($httpHandler, self::getClientNameUri());
return $this->clientName;
}
/**
* Sign a string using the default service account private key.
*
* This implementation uses IAM's signBlob API.
*
* @see https://cloud.google.com/iam/credentials/reference/rest/v1/projects.serviceAccounts/signBlob SignBlob
*
* @param string $stringToSign The string to sign.
* @param bool $forceOpenSsl [optional] Does not apply to this credentials
* type.
* @return string
*/
public function signBlob($stringToSign, $forceOpenSsl = \false)
{
$httpHandler = \WPMailSMTP\Vendor\Google\Auth\HttpHandler\HttpHandlerFactory::build(\WPMailSMTP\Vendor\Google\Auth\HttpHandler\HttpClientCache::getHttpClient());
// Providing a signer is useful for testing, but it's undocumented
// because it's not something a user would generally need to do.
$signer = $this->iam ?: new \WPMailSMTP\Vendor\Google\Auth\Iam($httpHandler);
$email = $this->getClientName($httpHandler);
$previousToken = $this->getLastReceivedToken();
$accessToken = $previousToken ? $previousToken['access_token'] : $this->fetchAuthToken($httpHandler)['access_token'];
return $signer->signBlob($email, $accessToken, $stringToSign);
}
/**
* Fetch the default Project ID from compute engine.
*
* Returns null if called outside GCE.
*
* @param callable $httpHandler Callback which delivers psr7 request
* @return string|null
*/
public function getProjectId(callable $httpHandler = null)
{
if ($this->projectId) {
return $this->projectId;
}
$httpHandler = $httpHandler ?: \WPMailSMTP\Vendor\Google\Auth\HttpHandler\HttpHandlerFactory::build(\WPMailSMTP\Vendor\Google\Auth\HttpHandler\HttpClientCache::getHttpClient());
if (!$this->hasCheckedOnGce) {
$this->isOnGce = self::onGce($httpHandler);
$this->hasCheckedOnGce = \true;
}
if (!$this->isOnGce) {
return null;
}
$this->projectId = $this->getFromMetadata($httpHandler, self::getProjectIdUri());
return $this->projectId;
}
/**
* Fetch the value of a GCE metadata server URI.
*
* @param callable $httpHandler An HTTP Handler to deliver PSR7 requests.
* @param string $uri The metadata URI.
* @return string
*/
private function getFromMetadata(callable $httpHandler, $uri)
{
$resp = $httpHandler(new \WPMailSMTP\Vendor\GuzzleHttp\Psr7\Request('GET', $uri, [self::FLAVOR_HEADER => 'Google']));
return (string) $resp->getBody();
}
/**
* Get the quota project used for this API request
*
* @return string|null
*/
public function getQuotaProject()
{
return $this->quotaProject;
}
}

View File

@ -0,0 +1,77 @@
<?php
/*
* Copyright 2015 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.
*/
namespace WPMailSMTP\Vendor\Google\Auth\Credentials;
/**
* Authenticates requests using IAM credentials.
*/
class IAMCredentials
{
const SELECTOR_KEY = 'x-goog-iam-authority-selector';
const TOKEN_KEY = 'x-goog-iam-authorization-token';
/**
* @var string
*/
private $selector;
/**
* @var string
*/
private $token;
/**
* @param $selector string the IAM selector
* @param $token string the IAM token
*/
public function __construct($selector, $token)
{
if (!\is_string($selector)) {
throw new \InvalidArgumentException('selector must be a string');
}
if (!\is_string($token)) {
throw new \InvalidArgumentException('token must be a string');
}
$this->selector = $selector;
$this->token = $token;
}
/**
* export a callback function which updates runtime metadata.
*
* @return array updateMetadata function
*/
public function getUpdateMetadataFunc()
{
return array($this, 'updateMetadata');
}
/**
* Updates metadata with the appropriate header metadata.
*
* @param array $metadata metadata hashmap
* @param string $unusedAuthUri optional auth uri
* @param callable $httpHandler callback which delivers psr7 request
* Note: this param is unused here, only included here for
* consistency with other credentials class
*
* @return array updated metadata hashmap
*/
public function updateMetadata($metadata, $unusedAuthUri = null, callable $httpHandler = null)
{
$metadata_copy = $metadata;
$metadata_copy[self::SELECTOR_KEY] = $this->selector;
$metadata_copy[self::TOKEN_KEY] = $this->token;
return $metadata_copy;
}
}

View File

@ -0,0 +1,64 @@
<?php
/*
* Copyright 2018 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.
*/
namespace WPMailSMTP\Vendor\Google\Auth\Credentials;
use WPMailSMTP\Vendor\Google\Auth\FetchAuthTokenInterface;
/**
* Provides a set of credentials that will always return an empty access token.
* This is useful for APIs which do not require authentication, for local
* service emulators, and for testing.
*/
class InsecureCredentials implements \WPMailSMTP\Vendor\Google\Auth\FetchAuthTokenInterface
{
/**
* @var array
*/
private $token = ['access_token' => ''];
/**
* Fetches the auth token. In this case it returns an empty string.
*
* @param callable $httpHandler
* @return array A set of auth related metadata, containing the following
* keys:
* - access_token (string)
*/
public function fetchAuthToken(callable $httpHandler = null)
{
return $this->token;
}
/**
* Returns the cache key. In this case it returns a null value, disabling
* caching.
*
* @return string|null
*/
public function getCacheKey()
{
return null;
}
/**
* Fetches the last received token. In this case, it returns the same empty string
* auth token.
*
* @return array
*/
public function getLastReceivedToken()
{
return $this->token;
}
}

View File

@ -0,0 +1,212 @@
<?php
/*
* Copyright 2015 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.
*/
namespace WPMailSMTP\Vendor\Google\Auth\Credentials;
use WPMailSMTP\Vendor\Google\Auth\CredentialsLoader;
use WPMailSMTP\Vendor\Google\Auth\GetQuotaProjectInterface;
use WPMailSMTP\Vendor\Google\Auth\OAuth2;
use WPMailSMTP\Vendor\Google\Auth\ProjectIdProviderInterface;
use WPMailSMTP\Vendor\Google\Auth\ServiceAccountSignerTrait;
use WPMailSMTP\Vendor\Google\Auth\SignBlobInterface;
use InvalidArgumentException;
/**
* ServiceAccountCredentials supports authorization using a Google service
* account.
*
* (cf https://developers.google.com/accounts/docs/OAuth2ServiceAccount)
*
* It's initialized using the json key file that's downloadable from developer
* console, which should contain a private_key and client_email fields that it
* uses.
*
* Use it with AuthTokenMiddleware to authorize http requests:
*
* use Google\Auth\Credentials\ServiceAccountCredentials;
* use Google\Auth\Middleware\AuthTokenMiddleware;
* use GuzzleHttp\Client;
* use GuzzleHttp\HandlerStack;
*
* $sa = new ServiceAccountCredentials(
* 'https://www.googleapis.com/auth/taskqueue',
* '/path/to/your/json/key_file.json'
* );
* $middleware = new AuthTokenMiddleware($sa);
* $stack = HandlerStack::create();
* $stack->push($middleware);
*
* $client = new Client([
* 'handler' => $stack,
* 'base_uri' => 'https://www.googleapis.com/taskqueue/v1beta2/projects/',
* 'auth' => 'google_auth' // authorize all requests
* ]);
*
* $res = $client->get('myproject/taskqueues/myqueue');
*/
class ServiceAccountCredentials extends \WPMailSMTP\Vendor\Google\Auth\CredentialsLoader implements \WPMailSMTP\Vendor\Google\Auth\GetQuotaProjectInterface, \WPMailSMTP\Vendor\Google\Auth\SignBlobInterface, \WPMailSMTP\Vendor\Google\Auth\ProjectIdProviderInterface
{
use ServiceAccountSignerTrait;
/**
* The OAuth2 instance used to conduct authorization.
*
* @var OAuth2
*/
protected $auth;
/**
* The quota project associated with the JSON credentials
*
* @var string
*/
protected $quotaProject;
/*
* @var string|null
*/
protected $projectId;
/**
* Create a new ServiceAccountCredentials.
*
* @param string|array $scope the scope of the access request, expressed
* either as an Array or as a space-delimited String.
* @param string|array $jsonKey JSON credential file path or JSON credentials
* as an associative array
* @param string $sub an email address account to impersonate, in situations when
* the service account has been delegated domain wide access.
* @param string $targetAudience The audience for the ID token.
*/
public function __construct($scope, $jsonKey, $sub = null, $targetAudience = null)
{
if (\is_string($jsonKey)) {
if (!\file_exists($jsonKey)) {
throw new \InvalidArgumentException('file does not exist');
}
$jsonKeyStream = \file_get_contents($jsonKey);
if (!($jsonKey = \json_decode($jsonKeyStream, \true))) {
throw new \LogicException('invalid json for auth config');
}
}
if (!\array_key_exists('client_email', $jsonKey)) {
throw new \InvalidArgumentException('json key is missing the client_email field');
}
if (!\array_key_exists('private_key', $jsonKey)) {
throw new \InvalidArgumentException('json key is missing the private_key field');
}
if (\array_key_exists('quota_project_id', $jsonKey)) {
$this->quotaProject = (string) $jsonKey['quota_project_id'];
}
if ($scope && $targetAudience) {
throw new \InvalidArgumentException('Scope and targetAudience cannot both be supplied');
}
$additionalClaims = [];
if ($targetAudience) {
$additionalClaims = ['target_audience' => $targetAudience];
}
$this->auth = new \WPMailSMTP\Vendor\Google\Auth\OAuth2(['audience' => self::TOKEN_CREDENTIAL_URI, 'issuer' => $jsonKey['client_email'], 'scope' => $scope, 'signingAlgorithm' => 'RS256', 'signingKey' => $jsonKey['private_key'], 'sub' => $sub, 'tokenCredentialUri' => self::TOKEN_CREDENTIAL_URI, 'additionalClaims' => $additionalClaims]);
$this->projectId = isset($jsonKey['project_id']) ? $jsonKey['project_id'] : null;
}
/**
* @param callable $httpHandler
*
* @return array A set of auth related metadata, containing the following
* keys:
* - access_token (string)
* - expires_in (int)
* - token_type (string)
*/
public function fetchAuthToken(callable $httpHandler = null)
{
return $this->auth->fetchAuthToken($httpHandler);
}
/**
* @return string
*/
public function getCacheKey()
{
$key = $this->auth->getIssuer() . ':' . $this->auth->getCacheKey();
if ($sub = $this->auth->getSub()) {
$key .= ':' . $sub;
}
return $key;
}
/**
* @return array
*/
public function getLastReceivedToken()
{
return $this->auth->getLastReceivedToken();
}
/**
* Get the project ID from the service account keyfile.
*
* Returns null if the project ID does not exist in the keyfile.
*
* @param callable $httpHandler Not used by this credentials type.
* @return string|null
*/
public function getProjectId(callable $httpHandler = null)
{
return $this->projectId;
}
/**
* Updates metadata with the authorization token.
*
* @param array $metadata metadata hashmap
* @param string $authUri optional auth uri
* @param callable $httpHandler callback which delivers psr7 request
* @return array updated metadata hashmap
*/
public function updateMetadata($metadata, $authUri = null, callable $httpHandler = null)
{
// scope exists. use oauth implementation
$scope = $this->auth->getScope();
if (!\is_null($scope)) {
return parent::updateMetadata($metadata, $authUri, $httpHandler);
}
// no scope found. create jwt with the auth uri
$credJson = array('private_key' => $this->auth->getSigningKey(), 'client_email' => $this->auth->getIssuer());
$jwtCreds = new \WPMailSMTP\Vendor\Google\Auth\Credentials\ServiceAccountJwtAccessCredentials($credJson);
return $jwtCreds->updateMetadata($metadata, $authUri, $httpHandler);
}
/**
* @param string $sub an email address account to impersonate, in situations when
* the service account has been delegated domain wide access.
*/
public function setSub($sub)
{
$this->auth->setSub($sub);
}
/**
* Get the client name from the keyfile.
*
* In this case, it returns the keyfile's client_email key.
*
* @param callable $httpHandler Not used by this credentials type.
* @return string
*/
public function getClientName(callable $httpHandler = null)
{
return $this->auth->getIssuer();
}
/**
* Get the quota project used for this API request
*
* @return string|null
*/
public function getQuotaProject()
{
return $this->quotaProject;
}
}

View File

@ -0,0 +1,158 @@
<?php
/*
* Copyright 2015 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.
*/
namespace WPMailSMTP\Vendor\Google\Auth\Credentials;
use WPMailSMTP\Vendor\Google\Auth\CredentialsLoader;
use WPMailSMTP\Vendor\Google\Auth\GetQuotaProjectInterface;
use WPMailSMTP\Vendor\Google\Auth\OAuth2;
use WPMailSMTP\Vendor\Google\Auth\ProjectIdProviderInterface;
use WPMailSMTP\Vendor\Google\Auth\ServiceAccountSignerTrait;
use WPMailSMTP\Vendor\Google\Auth\SignBlobInterface;
/**
* Authenticates requests using Google's Service Account credentials via
* JWT Access.
*
* This class allows authorizing requests for service accounts directly
* from credentials from a json key file downloaded from the developer
* console (via 'Generate new Json Key'). It is not part of any OAuth2
* flow, rather it creates a JWT and sends that as a credential.
*/
class ServiceAccountJwtAccessCredentials extends \WPMailSMTP\Vendor\Google\Auth\CredentialsLoader implements \WPMailSMTP\Vendor\Google\Auth\GetQuotaProjectInterface, \WPMailSMTP\Vendor\Google\Auth\SignBlobInterface, \WPMailSMTP\Vendor\Google\Auth\ProjectIdProviderInterface
{
use ServiceAccountSignerTrait;
/**
* The OAuth2 instance used to conduct authorization.
*
* @var OAuth2
*/
protected $auth;
/**
* The quota project associated with the JSON credentials
*/
protected $quotaProject;
/**
* Create a new ServiceAccountJwtAccessCredentials.
*
* @param string|array $jsonKey JSON credential file path or JSON credentials
* as an associative array
*/
public function __construct($jsonKey)
{
if (\is_string($jsonKey)) {
if (!\file_exists($jsonKey)) {
throw new \InvalidArgumentException('file does not exist');
}
$jsonKeyStream = \file_get_contents($jsonKey);
if (!($jsonKey = \json_decode($jsonKeyStream, \true))) {
throw new \LogicException('invalid json for auth config');
}
}
if (!\array_key_exists('client_email', $jsonKey)) {
throw new \InvalidArgumentException('json key is missing the client_email field');
}
if (!\array_key_exists('private_key', $jsonKey)) {
throw new \InvalidArgumentException('json key is missing the private_key field');
}
if (\array_key_exists('quota_project_id', $jsonKey)) {
$this->quotaProject = (string) $jsonKey['quota_project_id'];
}
$this->auth = new \WPMailSMTP\Vendor\Google\Auth\OAuth2(['issuer' => $jsonKey['client_email'], 'sub' => $jsonKey['client_email'], 'signingAlgorithm' => 'RS256', 'signingKey' => $jsonKey['private_key']]);
$this->projectId = isset($jsonKey['project_id']) ? $jsonKey['project_id'] : null;
}
/**
* Updates metadata with the authorization token.
*
* @param array $metadata metadata hashmap
* @param string $authUri optional auth uri
* @param callable $httpHandler callback which delivers psr7 request
* @return array updated metadata hashmap
*/
public function updateMetadata($metadata, $authUri = null, callable $httpHandler = null)
{
if (empty($authUri)) {
return $metadata;
}
$this->auth->setAudience($authUri);
return parent::updateMetadata($metadata, $authUri, $httpHandler);
}
/**
* Implements FetchAuthTokenInterface#fetchAuthToken.
*
* @param callable $httpHandler
*
* @return array|void A set of auth related metadata, containing the
* following keys:
* - access_token (string)
*/
public function fetchAuthToken(callable $httpHandler = null)
{
$audience = $this->auth->getAudience();
if (empty($audience)) {
return null;
}
$access_token = $this->auth->toJwt();
return array('access_token' => $access_token);
}
/**
* @return string
*/
public function getCacheKey()
{
return $this->auth->getCacheKey();
}
/**
* @return array
*/
public function getLastReceivedToken()
{
return $this->auth->getLastReceivedToken();
}
/**
* Get the project ID from the service account keyfile.
*
* Returns null if the project ID does not exist in the keyfile.
*
* @param callable $httpHandler Not used by this credentials type.
* @return string|null
*/
public function getProjectId(callable $httpHandler = null)
{
return $this->projectId;
}
/**
* Get the client name from the keyfile.
*
* In this case, it returns the keyfile's client_email key.
*
* @param callable $httpHandler Not used by this credentials type.
* @return string
*/
public function getClientName(callable $httpHandler = null)
{
return $this->auth->getIssuer();
}
/**
* Get the quota project used for this API request
*
* @return string|null
*/
public function getQuotaProject()
{
return $this->quotaProject;
}
}

View File

@ -0,0 +1,117 @@
<?php
/*
* Copyright 2015 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.
*/
namespace WPMailSMTP\Vendor\Google\Auth\Credentials;
use WPMailSMTP\Vendor\Google\Auth\CredentialsLoader;
use WPMailSMTP\Vendor\Google\Auth\GetQuotaProjectInterface;
use WPMailSMTP\Vendor\Google\Auth\OAuth2;
/**
* Authenticates requests using User Refresh credentials.
*
* This class allows authorizing requests from user refresh tokens.
*
* This the end of the result of a 3LO flow. E.g, the end result of
* 'gcloud auth login' saves a file with these contents in well known
* location
*
* @see [Application Default Credentials](http://goo.gl/mkAHpZ)
*/
class UserRefreshCredentials extends \WPMailSMTP\Vendor\Google\Auth\CredentialsLoader implements \WPMailSMTP\Vendor\Google\Auth\GetQuotaProjectInterface
{
/**
* The OAuth2 instance used to conduct authorization.
*
* @var OAuth2
*/
protected $auth;
/**
* The quota project associated with the JSON credentials
*/
protected $quotaProject;
/**
* Create a new UserRefreshCredentials.
*
* @param string|array $scope the scope of the access request, expressed
* either as an Array or as a space-delimited String.
* @param string|array $jsonKey JSON credential file path or JSON credentials
* as an associative array
*/
public function __construct($scope, $jsonKey)
{
if (\is_string($jsonKey)) {
if (!\file_exists($jsonKey)) {
throw new \InvalidArgumentException('file does not exist');
}
$jsonKeyStream = \file_get_contents($jsonKey);
if (!($jsonKey = \json_decode($jsonKeyStream, \true))) {
throw new \LogicException('invalid json for auth config');
}
}
if (!\array_key_exists('client_id', $jsonKey)) {
throw new \InvalidArgumentException('json key is missing the client_id field');
}
if (!\array_key_exists('client_secret', $jsonKey)) {
throw new \InvalidArgumentException('json key is missing the client_secret field');
}
if (!\array_key_exists('refresh_token', $jsonKey)) {
throw new \InvalidArgumentException('json key is missing the refresh_token field');
}
$this->auth = new \WPMailSMTP\Vendor\Google\Auth\OAuth2(['clientId' => $jsonKey['client_id'], 'clientSecret' => $jsonKey['client_secret'], 'refresh_token' => $jsonKey['refresh_token'], 'scope' => $scope, 'tokenCredentialUri' => self::TOKEN_CREDENTIAL_URI]);
if (\array_key_exists('quota_project_id', $jsonKey)) {
$this->quotaProject = (string) $jsonKey['quota_project_id'];
}
}
/**
* @param callable $httpHandler
*
* @return array A set of auth related metadata, containing the following
* keys:
* - access_token (string)
* - expires_in (int)
* - scope (string)
* - token_type (string)
* - id_token (string)
*/
public function fetchAuthToken(callable $httpHandler = null)
{
return $this->auth->fetchAuthToken($httpHandler);
}
/**
* @return string
*/
public function getCacheKey()
{
return $this->auth->getClientId() . ':' . $this->auth->getCacheKey();
}
/**
* @return array
*/
public function getLastReceivedToken()
{
return $this->auth->getLastReceivedToken();
}
/**
* Get the quota project used for this API request
*
* @return string|null
*/
public function getQuotaProject()
{
return $this->quotaProject;
}
}

View File

@ -0,0 +1,201 @@
<?php
/*
* Copyright 2015 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.
*/
namespace WPMailSMTP\Vendor\Google\Auth;
use WPMailSMTP\Vendor\Google\Auth\Credentials\InsecureCredentials;
use WPMailSMTP\Vendor\Google\Auth\Credentials\ServiceAccountCredentials;
use WPMailSMTP\Vendor\Google\Auth\Credentials\UserRefreshCredentials;
use WPMailSMTP\Vendor\GuzzleHttp\ClientInterface;
/**
* CredentialsLoader contains the behaviour used to locate and find default
* credentials files on the file system.
*/
abstract class CredentialsLoader implements \WPMailSMTP\Vendor\Google\Auth\FetchAuthTokenInterface, \WPMailSMTP\Vendor\Google\Auth\UpdateMetadataInterface
{
const TOKEN_CREDENTIAL_URI = 'https://oauth2.googleapis.com/token';
const ENV_VAR = 'GOOGLE_APPLICATION_CREDENTIALS';
const WELL_KNOWN_PATH = 'gcloud/application_default_credentials.json';
const NON_WINDOWS_WELL_KNOWN_PATH_BASE = '.config';
/**
* @param string $cause
* @return string
*/
private static function unableToReadEnv($cause)
{
$msg = 'Unable to read the credential file specified by ';
$msg .= ' GOOGLE_APPLICATION_CREDENTIALS: ';
$msg .= $cause;
return $msg;
}
/**
* @return bool
*/
private static function isOnWindows()
{
return \strtoupper(\substr(\PHP_OS, 0, 3)) === 'WIN';
}
/**
* Returns the currently available major Guzzle version.
*
* @return int
*/
private static function getGuzzleMajorVersion()
{
if (\defined('WPMailSMTP\\Vendor\\GuzzleHttp\\ClientInterface::MAJOR_VERSION')) {
return \WPMailSMTP\Vendor\GuzzleHttp\ClientInterface::MAJOR_VERSION;
}
if (\defined('WPMailSMTP\\Vendor\\GuzzleHttp\\ClientInterface::VERSION')) {
return (int) \substr(\WPMailSMTP\Vendor\GuzzleHttp\ClientInterface::VERSION, 0, 1);
}
throw new \Exception('Version not supported');
}
/**
* Load a JSON key from the path specified in the environment.
*
* Load a JSON key from the path specified in the environment
* variable GOOGLE_APPLICATION_CREDENTIALS. Return null if
* GOOGLE_APPLICATION_CREDENTIALS is not specified.
*
* @return array|null JSON key | null
*/
public static function fromEnv()
{
$path = \getenv(self::ENV_VAR);
if (empty($path)) {
return;
}
if (!\file_exists($path)) {
$cause = 'file ' . $path . ' does not exist';
throw new \DomainException(self::unableToReadEnv($cause));
}
$jsonKey = \file_get_contents($path);
return \json_decode($jsonKey, \true);
}
/**
* Load a JSON key from a well known path.
*
* The well known path is OS dependent:
*
* * windows: %APPDATA%/gcloud/application_default_credentials.json
* * others: $HOME/.config/gcloud/application_default_credentials.json
*
* If the file does not exist, this returns null.
*
* @return array|null JSON key | null
*/
public static function fromWellKnownFile()
{
$rootEnv = self::isOnWindows() ? 'APPDATA' : 'HOME';
$path = [\getenv($rootEnv)];
if (!self::isOnWindows()) {
$path[] = self::NON_WINDOWS_WELL_KNOWN_PATH_BASE;
}
$path[] = self::WELL_KNOWN_PATH;
$path = \implode(\DIRECTORY_SEPARATOR, $path);
if (!\file_exists($path)) {
return;
}
$jsonKey = \file_get_contents($path);
return \json_decode($jsonKey, \true);
}
/**
* Create a new Credentials instance.
*
* @param string|array $scope the scope of the access request, expressed
* either as an Array or as a space-delimited String.
* @param array $jsonKey the JSON credentials.
* @return ServiceAccountCredentials|UserRefreshCredentials
*/
public static function makeCredentials($scope, array $jsonKey)
{
if (!\array_key_exists('type', $jsonKey)) {
throw new \InvalidArgumentException('json key is missing the type field');
}
if ($jsonKey['type'] == 'service_account') {
return new \WPMailSMTP\Vendor\Google\Auth\Credentials\ServiceAccountCredentials($scope, $jsonKey);
}
if ($jsonKey['type'] == 'authorized_user') {
return new \WPMailSMTP\Vendor\Google\Auth\Credentials\UserRefreshCredentials($scope, $jsonKey);
}
throw new \InvalidArgumentException('invalid value in the type field');
}
/**
* Create an authorized HTTP Client from an instance of FetchAuthTokenInterface.
*
* @param FetchAuthTokenInterface $fetcher is used to fetch the auth token
* @param array $httpClientOptions (optional) Array of request options to apply.
* @param callable $httpHandler (optional) http client to fetch the token.
* @param callable $tokenCallback (optional) function to be called when a new token is fetched.
* @return \GuzzleHttp\Client
*/
public static function makeHttpClient(\WPMailSMTP\Vendor\Google\Auth\FetchAuthTokenInterface $fetcher, array $httpClientOptions = [], callable $httpHandler = null, callable $tokenCallback = null)
{
if (self::getGuzzleMajorVersion() === 5) {
$client = new \WPMailSMTP\Vendor\GuzzleHttp\Client($httpClientOptions);
$client->setDefaultOption('auth', 'google_auth');
$subscriber = new \WPMailSMTP\Vendor\Google\Auth\Subscriber\AuthTokenSubscriber($fetcher, $httpHandler, $tokenCallback);
$client->getEmitter()->attach($subscriber);
return $client;
}
$middleware = new \WPMailSMTP\Vendor\Google\Auth\Middleware\AuthTokenMiddleware($fetcher, $httpHandler, $tokenCallback);
$stack = \WPMailSMTP\Vendor\GuzzleHttp\HandlerStack::create();
$stack->push($middleware);
return new \WPMailSMTP\Vendor\GuzzleHttp\Client(['handler' => $stack, 'auth' => 'google_auth'] + $httpClientOptions);
}
/**
* Create a new instance of InsecureCredentials.
*
* @return InsecureCredentials
*/
public static function makeInsecureCredentials()
{
return new \WPMailSMTP\Vendor\Google\Auth\Credentials\InsecureCredentials();
}
/**
* export a callback function which updates runtime metadata.
*
* @return array updateMetadata function
* @deprecated
*/
public function getUpdateMetadataFunc()
{
return array($this, 'updateMetadata');
}
/**
* Updates metadata with the authorization token.
*
* @param array $metadata metadata hashmap
* @param string $authUri optional auth uri
* @param callable $httpHandler callback which delivers psr7 request
* @return array updated metadata hashmap
*/
public function updateMetadata($metadata, $authUri = null, callable $httpHandler = null)
{
if (isset($metadata[self::AUTH_METADATA_KEY])) {
// Auth metadata has already been set
return $metdadata;
}
$result = $this->fetchAuthToken($httpHandler);
if (!isset($result['access_token'])) {
return $metadata;
}
$metadata_copy = $metadata;
$metadata_copy[self::AUTH_METADATA_KEY] = array('Bearer ' . $result['access_token']);
return $metadata_copy;
}
}

View File

@ -0,0 +1,180 @@
<?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.
*/
namespace WPMailSMTP\Vendor\Google\Auth;
use WPMailSMTP\Vendor\Psr\Cache\CacheItemPoolInterface;
/**
* A class to implement caching for any object implementing
* FetchAuthTokenInterface
*/
class FetchAuthTokenCache implements \WPMailSMTP\Vendor\Google\Auth\FetchAuthTokenInterface, \WPMailSMTP\Vendor\Google\Auth\GetQuotaProjectInterface, \WPMailSMTP\Vendor\Google\Auth\SignBlobInterface, \WPMailSMTP\Vendor\Google\Auth\ProjectIdProviderInterface, \WPMailSMTP\Vendor\Google\Auth\UpdateMetadataInterface
{
use CacheTrait;
/**
* @var FetchAuthTokenInterface
*/
private $fetcher;
/**
* @var array
*/
private $cacheConfig;
/**
* @var CacheItemPoolInterface
*/
private $cache;
/**
* @param FetchAuthTokenInterface $fetcher A credentials fetcher
* @param array $cacheConfig Configuration for the cache
* @param CacheItemPoolInterface $cache
*/
public function __construct(\WPMailSMTP\Vendor\Google\Auth\FetchAuthTokenInterface $fetcher, array $cacheConfig = null, \WPMailSMTP\Vendor\Psr\Cache\CacheItemPoolInterface $cache)
{
$this->fetcher = $fetcher;
$this->cache = $cache;
$this->cacheConfig = \array_merge(['lifetime' => 1500, 'prefix' => ''], (array) $cacheConfig);
}
/**
* Implements FetchAuthTokenInterface#fetchAuthToken.
*
* Checks the cache for a valid auth token and fetches the auth tokens
* from the supplied fetcher.
*
* @param callable $httpHandler callback which delivers psr7 request
* @return array the response
* @throws \Exception
*/
public function fetchAuthToken(callable $httpHandler = null)
{
// Use the cached value if its available.
//
// TODO: correct caching; update the call to setCachedValue to set the expiry
// to the value returned with the auth token.
//
// TODO: correct caching; enable the cache to be cleared.
$cacheKey = $this->fetcher->getCacheKey();
$cached = $this->getCachedValue($cacheKey);
if (\is_array($cached)) {
if (empty($cached['expires_at'])) {
// If there is no expiration data, assume token is not expired.
// (for JwtAccess and ID tokens)
return $cached;
}
if (\time() < $cached['expires_at']) {
// access token is not expired
return $cached;
}
}
$auth_token = $this->fetcher->fetchAuthToken($httpHandler);
if (isset($auth_token['access_token']) || isset($auth_token['id_token'])) {
$this->setCachedValue($cacheKey, $auth_token);
}
return $auth_token;
}
/**
* @return string
*/
public function getCacheKey()
{
return $this->getFullCacheKey($this->fetcher->getCacheKey());
}
/**
* @return array|null
*/
public function getLastReceivedToken()
{
return $this->fetcher->getLastReceivedToken();
}
/**
* Get the client name from the fetcher.
*
* @param callable $httpHandler An HTTP handler to deliver PSR7 requests.
* @return string
*/
public function getClientName(callable $httpHandler = null)
{
return $this->fetcher->getClientName($httpHandler);
}
/**
* Sign a blob using the fetcher.
*
* @param string $stringToSign The string to sign.
* @param bool $forceOpenSsl Require use of OpenSSL for local signing. Does
* not apply to signing done using external services. **Defaults to**
* `false`.
* @return string The resulting signature.
* @throws \RuntimeException If the fetcher does not implement
* `Google\Auth\SignBlobInterface`.
*/
public function signBlob($stringToSign, $forceOpenSsl = \false)
{
if (!$this->fetcher instanceof \WPMailSMTP\Vendor\Google\Auth\SignBlobInterface) {
throw new \RuntimeException('Credentials fetcher does not implement ' . 'Google\\Auth\\SignBlobInterface');
}
return $this->fetcher->signBlob($stringToSign, $forceOpenSsl);
}
/**
* Get the quota project used for this API request from the credentials
* fetcher.
*
* @return string|null
*/
public function getQuotaProject()
{
if ($this->fetcher instanceof \WPMailSMTP\Vendor\Google\Auth\GetQuotaProjectInterface) {
return $this->fetcher->getQuotaProject();
}
}
/*
* Get the Project ID from the fetcher.
*
* @param callable $httpHandler Callback which delivers psr7 request
* @return string|null
* @throws \RuntimeException If the fetcher does not implement
* `Google\Auth\ProvidesProjectIdInterface`.
*/
public function getProjectId(callable $httpHandler = null)
{
if (!$this->fetcher instanceof \WPMailSMTP\Vendor\Google\Auth\ProjectIdProviderInterface) {
throw new \RuntimeException('Credentials fetcher does not implement ' . 'Google\\Auth\\ProvidesProjectIdInterface');
}
return $this->fetcher->getProjectId($httpHandler);
}
/**
* Updates metadata with the authorization token.
*
* @param array $metadata metadata hashmap
* @param string $authUri optional auth uri
* @param callable $httpHandler callback which delivers psr7 request
* @return array updated metadata hashmap
* @throws \RuntimeException If the fetcher does not implement
* `Google\Auth\UpdateMetadataInterface`.
*/
public function updateMetadata($metadata, $authUri = null, callable $httpHandler = null)
{
if (!$this->fetcher instanceof \WPMailSMTP\Vendor\Google\Auth\UpdateMetadataInterface) {
throw new \RuntimeException('Credentials fetcher does not implement ' . 'Google\\Auth\\UpdateMetadataInterface');
}
// Set the `Authentication` header from the cache, so it is not set
// again by the fetcher
$result = $this->fetchAuthToken($httpHandler);
if (isset($result['access_token'])) {
$metadata[self::AUTH_METADATA_KEY] = ['Bearer ' . $result['access_token']];
}
return $this->fetcher->updateMetadata($metadata, $authUri, $httpHandler);
}
}

View File

@ -0,0 +1,52 @@
<?php
/*
* Copyright 2015 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.
*/
namespace WPMailSMTP\Vendor\Google\Auth;
/**
* An interface implemented by objects that can fetch auth tokens.
*/
interface FetchAuthTokenInterface
{
/**
* Fetches the auth tokens based on the current state.
*
* @param callable $httpHandler callback which delivers psr7 request
* @return array a hash of auth tokens
*/
public function fetchAuthToken(callable $httpHandler = null);
/**
* Obtains a key that can used to cache the results of #fetchAuthToken.
*
* If the value is empty, the auth token is not cached.
*
* @return string a key that may be used to cache the auth token.
*/
public function getCacheKey();
/**
* Returns an associative array with the token and
* expiration time.
*
* @return null|array {
* The last received access token.
*
* @var string $access_token The access token string.
* @var int $expires_at The time the token expires as a UNIX timestamp.
* }
*/
public function getLastReceivedToken();
}

View File

@ -0,0 +1,78 @@
<?php
/*
* Copyright 2020 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.
*/
namespace WPMailSMTP\Vendor\Google\Auth;
use WPMailSMTP\Vendor\Google\Auth\Credentials\GCECredentials;
use WPMailSMTP\Vendor\Psr\Cache\CacheItemPoolInterface;
/**
* A class to implement caching for calls to GCECredentials::onGce. This class
* is used automatically when you pass a `Psr\Cache\CacheItemPoolInterface`
* cache object to `ApplicationDefaultCredentials::getCredentials`.
*
* ```
* $sysvCache = new Google\Auth\SysvCacheItemPool();
* $creds = Google\Auth\ApplicationDefaultCredentials::getCredentials(
* $scope,
* null,
* null,
* $sysvCache
* );
* ```
*/
class GCECache
{
const GCE_CACHE_KEY = 'google_auth_on_gce_cache';
use CacheTrait;
/**
* @var array
*/
private $cacheConfig;
/**
* @var CacheItemPoolInterface
*/
private $cache;
/**
* @param array $cacheConfig Configuration for the cache
* @param CacheItemPoolInterface $cache
*/
public function __construct(array $cacheConfig = null, \WPMailSMTP\Vendor\Psr\Cache\CacheItemPoolInterface $cache = null)
{
$this->cache = $cache;
$this->cacheConfig = \array_merge(['lifetime' => 1500, 'prefix' => ''], (array) $cacheConfig);
}
/**
* Caches the result of onGce so the metadata server is not called multiple
* times.
*
* @param callable $httpHandler callback which delivers psr7 request
* @return bool True if this a GCEInstance, false otherwise
*/
public function onGce(callable $httpHandler = null)
{
if (\is_null($this->cache)) {
return \WPMailSMTP\Vendor\Google\Auth\Credentials\GCECredentials::onGce($httpHandler);
}
$cacheKey = self::GCE_CACHE_KEY;
$onGce = $this->getCachedValue($cacheKey);
if (\is_null($onGce)) {
$onGce = \WPMailSMTP\Vendor\Google\Auth\Credentials\GCECredentials::onGce($httpHandler);
$this->setCachedValue($cacheKey, $onGce);
}
return $onGce;
}
}

View File

@ -0,0 +1,32 @@
<?php
/*
* Copyright 2019 Google LLC
*
* 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.
*/
namespace WPMailSMTP\Vendor\Google\Auth;
/**
* An interface implemented by objects that can get quota projects.
*/
interface GetQuotaProjectInterface
{
const X_GOOG_USER_PROJECT_HEADER = 'X-Goog-User-Project';
/**
* Get the quota project used for this API request
*
* @return string|null
*/
public function getQuotaProject();
}

View File

@ -0,0 +1,90 @@
<?php
/**
* Copyright 2015 Google Inc. All Rights Reserved.
*
* 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.
*/
namespace WPMailSMTP\Vendor\Google\Auth\HttpHandler;
use Exception;
use WPMailSMTP\Vendor\GuzzleHttp\ClientInterface;
use WPMailSMTP\Vendor\GuzzleHttp\Message\ResponseInterface as Guzzle5ResponseInterface;
use WPMailSMTP\Vendor\GuzzleHttp\Promise\Promise;
use WPMailSMTP\Vendor\GuzzleHttp\Promise\RejectedPromise;
use WPMailSMTP\Vendor\GuzzleHttp\Psr7\Response;
use WPMailSMTP\Vendor\Psr\Http\Message\RequestInterface;
use WPMailSMTP\Vendor\Psr\Http\Message\ResponseInterface;
class Guzzle5HttpHandler
{
/**
* @var ClientInterface
*/
private $client;
/**
* @param ClientInterface $client
*/
public function __construct(\WPMailSMTP\Vendor\GuzzleHttp\ClientInterface $client)
{
$this->client = $client;
}
/**
* Accepts a PSR-7 Request and an array of options and returns a PSR-7 response.
*
* @param RequestInterface $request
* @param array $options
* @return ResponseInterface
*/
public function __invoke(\WPMailSMTP\Vendor\Psr\Http\Message\RequestInterface $request, array $options = [])
{
$response = $this->client->send($this->createGuzzle5Request($request, $options));
return $this->createPsr7Response($response);
}
/**
* Accepts a PSR-7 request and an array of options and returns a PromiseInterface
*
* @param RequestInterface $request
* @param array $options
* @return Promise
*/
public function async(\WPMailSMTP\Vendor\Psr\Http\Message\RequestInterface $request, array $options = [])
{
if (!\class_exists('WPMailSMTP\\Vendor\\GuzzleHttp\\Promise\\Promise')) {
throw new \Exception('Install guzzlehttp/promises to use async with Guzzle 5');
}
$futureResponse = $this->client->send($this->createGuzzle5Request($request, ['future' => \true] + $options));
$promise = new \WPMailSMTP\Vendor\GuzzleHttp\Promise\Promise(function () use($futureResponse) {
try {
$futureResponse->wait();
} catch (\Exception $e) {
// The promise is already delivered when the exception is
// thrown, so don't rethrow it.
}
}, [$futureResponse, 'cancel']);
$futureResponse->then([$promise, 'resolve'], [$promise, 'reject']);
return $promise->then(function (\WPMailSMTP\Vendor\GuzzleHttp\Message\ResponseInterface $response) {
// Adapt the Guzzle 5 Response to a PSR-7 Response.
return $this->createPsr7Response($response);
}, function (\Exception $e) {
return new \WPMailSMTP\Vendor\GuzzleHttp\Promise\RejectedPromise($e);
});
}
private function createGuzzle5Request(\WPMailSMTP\Vendor\Psr\Http\Message\RequestInterface $request, array $options)
{
return $this->client->createRequest($request->getMethod(), $request->getUri(), \array_merge_recursive(['headers' => $request->getHeaders(), 'body' => $request->getBody()], $options));
}
private function createPsr7Response(\WPMailSMTP\Vendor\GuzzleHttp\Message\ResponseInterface $response)
{
return new \WPMailSMTP\Vendor\GuzzleHttp\Psr7\Response($response->getStatusCode(), $response->getHeaders() ?: [], $response->getBody(), $response->getProtocolVersion(), $response->getReasonPhrase());
}
}

View File

@ -0,0 +1,59 @@
<?php
/**
* Copyright 2015 Google Inc. All Rights Reserved.
*
* 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.
*/
namespace WPMailSMTP\Vendor\Google\Auth\HttpHandler;
use WPMailSMTP\Vendor\GuzzleHttp\ClientInterface;
use WPMailSMTP\Vendor\Psr\Http\Message\RequestInterface;
use WPMailSMTP\Vendor\Psr\Http\Message\ResponseInterface;
class Guzzle6HttpHandler
{
/**
* @var ClientInterface
*/
private $client;
/**
* @param ClientInterface $client
*/
public function __construct(\WPMailSMTP\Vendor\GuzzleHttp\ClientInterface $client)
{
$this->client = $client;
}
/**
* Accepts a PSR-7 request and an array of options and returns a PSR-7 response.
*
* @param RequestInterface $request
* @param array $options
* @return ResponseInterface
*/
public function __invoke(\WPMailSMTP\Vendor\Psr\Http\Message\RequestInterface $request, array $options = [])
{
return $this->client->send($request, $options);
}
/**
* Accepts a PSR-7 request and an array of options and returns a PromiseInterface
*
* @param RequestInterface $request
* @param array $options
*
* @return \GuzzleHttp\Promise\PromiseInterface
*/
public function async(\WPMailSMTP\Vendor\Psr\Http\Message\RequestInterface $request, array $options = [])
{
return $this->client->sendAsync($request, $options);
}
}

View File

@ -0,0 +1,22 @@
<?php
/**
* Copyright 2020 Google LLC
*
* 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.
*/
namespace WPMailSMTP\Vendor\Google\Auth\HttpHandler;
class Guzzle7HttpHandler extends \WPMailSMTP\Vendor\Google\Auth\HttpHandler\Guzzle6HttpHandler
{
}

View File

@ -0,0 +1,51 @@
<?php
/*
* Copyright 2019 Google LLC
*
* 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.
*/
namespace WPMailSMTP\Vendor\Google\Auth\HttpHandler;
use WPMailSMTP\Vendor\GuzzleHttp\ClientInterface;
/**
* Stores an HTTP Client in order to prevent multiple instantiations.
*/
class HttpClientCache
{
/**
* @var ClientInterface|null
*/
private static $httpClient;
/**
* Cache an HTTP Client for later calls.
*
* Passing null will unset the cached client.
*
* @param ClientInterface|null $client
* @return void
*/
public static function setHttpClient(\WPMailSMTP\Vendor\GuzzleHttp\ClientInterface $client = null)
{
self::$httpClient = $client;
}
/**
* Get the stored HTTP Client, or null.
*
* @return ClientInterface|null
*/
public static function getHttpClient()
{
return self::$httpClient;
}
}

View File

@ -0,0 +1,51 @@
<?php
/**
* Copyright 2015 Google Inc. All Rights Reserved.
*
* 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.
*/
namespace WPMailSMTP\Vendor\Google\Auth\HttpHandler;
use WPMailSMTP\Vendor\GuzzleHttp\Client;
use WPMailSMTP\Vendor\GuzzleHttp\ClientInterface;
class HttpHandlerFactory
{
/**
* Builds out a default http handler for the installed version of guzzle.
*
* @param ClientInterface $client
* @return Guzzle5HttpHandler|Guzzle6HttpHandler|Guzzle7HttpHandler
* @throws \Exception
*/
public static function build(\WPMailSMTP\Vendor\GuzzleHttp\ClientInterface $client = null)
{
$client = $client ?: new \WPMailSMTP\Vendor\GuzzleHttp\Client();
$version = null;
if (\defined('WPMailSMTP\\Vendor\\GuzzleHttp\\ClientInterface::MAJOR_VERSION')) {
$version = \WPMailSMTP\Vendor\GuzzleHttp\ClientInterface::MAJOR_VERSION;
} elseif (\defined('WPMailSMTP\\Vendor\\GuzzleHttp\\ClientInterface::VERSION')) {
$version = (int) \substr(\WPMailSMTP\Vendor\GuzzleHttp\ClientInterface::VERSION, 0, 1);
}
switch ($version) {
case 5:
return new \WPMailSMTP\Vendor\Google\Auth\HttpHandler\Guzzle5HttpHandler($client);
case 6:
return new \WPMailSMTP\Vendor\Google\Auth\HttpHandler\Guzzle6HttpHandler($client);
case 7:
return new \WPMailSMTP\Vendor\Google\Auth\HttpHandler\Guzzle7HttpHandler($client);
default:
throw new \Exception('Version not supported');
}
}
}

View File

@ -0,0 +1,78 @@
<?php
/*
* Copyright 2019 Google LLC
*
* 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.
*/
namespace WPMailSMTP\Vendor\Google\Auth;
use WPMailSMTP\Vendor\Google\Auth\HttpHandler\HttpClientCache;
use WPMailSMTP\Vendor\Google\Auth\HttpHandler\HttpHandlerFactory;
use WPMailSMTP\Vendor\GuzzleHttp\Psr7;
/**
* Tools for using the IAM API.
*
* @see https://cloud.google.com/iam/docs IAM Documentation
*/
class Iam
{
const IAM_API_ROOT = 'https://iamcredentials.googleapis.com/v1';
const SIGN_BLOB_PATH = '%s:signBlob?alt=json';
const SERVICE_ACCOUNT_NAME = 'projects/-/serviceAccounts/%s';
/**
* @var callable
*/
private $httpHandler;
/**
* @param callable $httpHandler [optional] The HTTP Handler to send requests.
*/
public function __construct(callable $httpHandler = null)
{
$this->httpHandler = $httpHandler ?: \WPMailSMTP\Vendor\Google\Auth\HttpHandler\HttpHandlerFactory::build(\WPMailSMTP\Vendor\Google\Auth\HttpHandler\HttpClientCache::getHttpClient());
}
/**
* Sign a string using the IAM signBlob API.
*
* Note that signing using IAM requires your service account to have the
* `iam.serviceAccounts.signBlob` permission, part of the "Service Account
* Token Creator" IAM role.
*
* @param string $email The service account email.
* @param string $accessToken An access token from the service account.
* @param string $stringToSign The string to be signed.
* @param array $delegates [optional] A list of service account emails to
* add to the delegate chain. If omitted, the value of `$email` will
* be used.
* @return string The signed string, base64-encoded.
*/
public function signBlob($email, $accessToken, $stringToSign, array $delegates = [])
{
$httpHandler = $this->httpHandler;
$name = \sprintf(self::SERVICE_ACCOUNT_NAME, $email);
$uri = self::IAM_API_ROOT . '/' . \sprintf(self::SIGN_BLOB_PATH, $name);
if ($delegates) {
foreach ($delegates as &$delegate) {
$delegate = \sprintf(self::SERVICE_ACCOUNT_NAME, $delegate);
}
} else {
$delegates = [$name];
}
$body = ['delegates' => $delegates, 'payload' => \base64_encode($stringToSign)];
$headers = ['Authorization' => 'Bearer ' . $accessToken];
$request = new \WPMailSMTP\Vendor\GuzzleHttp\Psr7\Request('POST', $uri, $headers, \WPMailSMTP\Vendor\GuzzleHttp\Psr7\stream_for(\json_encode($body)));
$res = $httpHandler($request);
$body = \json_decode((string) $res->getBody(), \true);
return $body['signedBlob'];
}
}

View File

@ -0,0 +1,125 @@
<?php
/*
* Copyright 2015 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.
*/
namespace WPMailSMTP\Vendor\Google\Auth\Middleware;
use WPMailSMTP\Vendor\Google\Auth\FetchAuthTokenInterface;
use WPMailSMTP\Vendor\Google\Auth\GetQuotaProjectInterface;
use WPMailSMTP\Vendor\Psr\Http\Message\RequestInterface;
/**
* AuthTokenMiddleware is a Guzzle Middleware that adds an Authorization header
* provided by an object implementing FetchAuthTokenInterface.
*
* The FetchAuthTokenInterface#fetchAuthToken is used to obtain a hash; one of
* the values value in that hash is added as the authorization header.
*
* Requests will be accessed with the authorization header:
*
* 'authorization' 'Bearer <value of auth_token>'
*/
class AuthTokenMiddleware
{
/**
* @var callback
*/
private $httpHandler;
/**
* @var FetchAuthTokenInterface
*/
private $fetcher;
/**
* @var callable
*/
private $tokenCallback;
/**
* Creates a new AuthTokenMiddleware.
*
* @param FetchAuthTokenInterface $fetcher is used to fetch the auth token
* @param callable $httpHandler (optional) callback which delivers psr7 request
* @param callable $tokenCallback (optional) function to be called when a new token is fetched.
*/
public function __construct(\WPMailSMTP\Vendor\Google\Auth\FetchAuthTokenInterface $fetcher, callable $httpHandler = null, callable $tokenCallback = null)
{
$this->fetcher = $fetcher;
$this->httpHandler = $httpHandler;
$this->tokenCallback = $tokenCallback;
}
/**
* Updates the request with an Authorization header when auth is 'google_auth'.
*
* use Google\Auth\Middleware\AuthTokenMiddleware;
* use Google\Auth\OAuth2;
* use GuzzleHttp\Client;
* use GuzzleHttp\HandlerStack;
*
* $config = [..<oauth config param>.];
* $oauth2 = new OAuth2($config)
* $middleware = new AuthTokenMiddleware($oauth2);
* $stack = HandlerStack::create();
* $stack->push($middleware);
*
* $client = new Client([
* 'handler' => $stack,
* 'base_uri' => 'https://www.googleapis.com/taskqueue/v1beta2/projects/',
* 'auth' => 'google_auth' // authorize all requests
* ]);
*
* $res = $client->get('myproject/taskqueues/myqueue');
*
* @param callable $handler
* @return \Closure
*/
public function __invoke(callable $handler)
{
return function (\WPMailSMTP\Vendor\Psr\Http\Message\RequestInterface $request, array $options) use($handler) {
// Requests using "auth"="google_auth" will be authorized.
if (!isset($options['auth']) || $options['auth'] !== 'google_auth') {
return $handler($request, $options);
}
$request = $request->withHeader('authorization', 'Bearer ' . $this->fetchToken());
if ($quotaProject = $this->getQuotaProject()) {
$request = $request->withHeader(\WPMailSMTP\Vendor\Google\Auth\GetQuotaProjectInterface::X_GOOG_USER_PROJECT_HEADER, $quotaProject);
}
return $handler($request, $options);
};
}
/**
* Call fetcher to fetch the token.
*
* @return string
*/
private function fetchToken()
{
$auth_tokens = $this->fetcher->fetchAuthToken($this->httpHandler);
if (\array_key_exists('access_token', $auth_tokens)) {
// notify the callback if applicable
if ($this->tokenCallback) {
\call_user_func($this->tokenCallback, $this->fetcher->getCacheKey(), $auth_tokens['access_token']);
}
return $auth_tokens['access_token'];
}
if (\array_key_exists('id_token', $auth_tokens)) {
return $auth_tokens['id_token'];
}
}
private function getQuotaProject()
{
if ($this->fetcher instanceof \WPMailSMTP\Vendor\Google\Auth\GetQuotaProjectInterface) {
return $this->fetcher->getQuotaProject();
}
}
}

View File

@ -0,0 +1,148 @@
<?php
/*
* Copyright 2015 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.
*/
namespace WPMailSMTP\Vendor\Google\Auth\Middleware;
use WPMailSMTP\Vendor\Google\Auth\CacheTrait;
use WPMailSMTP\Vendor\Psr\Cache\CacheItemPoolInterface;
use WPMailSMTP\Vendor\Psr\Http\Message\RequestInterface;
/**
* ScopedAccessTokenMiddleware is a Guzzle Middleware that adds an Authorization
* header provided by a closure.
*
* The closure returns an access token, taking the scope, either a single
* string or an array of strings, as its value. If provided, a cache will be
* used to preserve the access token for a given lifetime.
*
* Requests will be accessed with the authorization header:
*
* 'authorization' 'Bearer <value of auth_token>'
*/
class ScopedAccessTokenMiddleware
{
use CacheTrait;
const DEFAULT_CACHE_LIFETIME = 1500;
/**
* @var CacheItemPoolInterface
*/
private $cache;
/**
* @var array configuration
*/
private $cacheConfig;
/**
* @var callable
*/
private $tokenFunc;
/**
* @var array|string
*/
private $scopes;
/**
* Creates a new ScopedAccessTokenMiddleware.
*
* @param callable $tokenFunc a token generator function
* @param array|string $scopes the token authentication scopes
* @param array $cacheConfig configuration for the cache when it's present
* @param CacheItemPoolInterface $cache an implementation of CacheItemPoolInterface
*/
public function __construct(callable $tokenFunc, $scopes, array $cacheConfig = null, \WPMailSMTP\Vendor\Psr\Cache\CacheItemPoolInterface $cache = null)
{
$this->tokenFunc = $tokenFunc;
if (!(\is_string($scopes) || \is_array($scopes))) {
throw new \InvalidArgumentException('wants scope should be string or array');
}
$this->scopes = $scopes;
if (!\is_null($cache)) {
$this->cache = $cache;
$this->cacheConfig = \array_merge(['lifetime' => self::DEFAULT_CACHE_LIFETIME, 'prefix' => ''], $cacheConfig);
}
}
/**
* Updates the request with an Authorization header when auth is 'scoped'.
*
* E.g this could be used to authenticate using the AppEngine
* AppIdentityService.
*
* use google\appengine\api\app_identity\AppIdentityService;
* use Google\Auth\Middleware\ScopedAccessTokenMiddleware;
* use GuzzleHttp\Client;
* use GuzzleHttp\HandlerStack;
*
* $scope = 'https://www.googleapis.com/auth/taskqueue'
* $middleware = new ScopedAccessTokenMiddleware(
* 'AppIdentityService::getAccessToken',
* $scope,
* [ 'prefix' => 'Google\Auth\ScopedAccessToken::' ],
* $cache = new Memcache()
* );
* $stack = HandlerStack::create();
* $stack->push($middleware);
*
* $client = new Client([
* 'handler' => $stack,
* 'base_url' => 'https://www.googleapis.com/taskqueue/v1beta2/projects/',
* 'auth' => 'scoped' // authorize all requests
* ]);
*
* $res = $client->get('myproject/taskqueues/myqueue');
*
* @param callable $handler
* @return \Closure
*/
public function __invoke(callable $handler)
{
return function (\WPMailSMTP\Vendor\Psr\Http\Message\RequestInterface $request, array $options) use($handler) {
// Requests using "auth"="scoped" will be authorized.
if (!isset($options['auth']) || $options['auth'] !== 'scoped') {
return $handler($request, $options);
}
$request = $request->withHeader('authorization', 'Bearer ' . $this->fetchToken());
return $handler($request, $options);
};
}
/**
* @return string
*/
private function getCacheKey()
{
$key = null;
if (\is_string($this->scopes)) {
$key .= $this->scopes;
} elseif (\is_array($this->scopes)) {
$key .= \implode(':', $this->scopes);
}
return $key;
}
/**
* Determine if token is available in the cache, if not call tokenFunc to
* fetch it.
*
* @return string
*/
private function fetchToken()
{
$cacheKey = $this->getCacheKey();
$cached = $this->getCachedValue($cacheKey);
if (!empty($cached)) {
return $cached;
}
$token = \call_user_func($this->tokenFunc, $this->scopes);
$this->setCachedValue($cacheKey, $token);
return $token;
}
}

View File

@ -0,0 +1,86 @@
<?php
/*
* Copyright 2015 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.
*/
namespace WPMailSMTP\Vendor\Google\Auth\Middleware;
use WPMailSMTP\Vendor\GuzzleHttp\Psr7;
use WPMailSMTP\Vendor\Psr\Http\Message\RequestInterface;
/**
* SimpleMiddleware is a Guzzle Middleware that implements Google's Simple API
* access.
*
* Requests are accessed using the Simple API access developer key.
*/
class SimpleMiddleware
{
/**
* @var array
*/
private $config;
/**
* Create a new Simple plugin.
*
* The configuration array expects one option
* - key: required, otherwise InvalidArgumentException is thrown
*
* @param array $config Configuration array
*/
public function __construct(array $config)
{
if (!isset($config['key'])) {
throw new \InvalidArgumentException('requires a key to have been set');
}
$this->config = \array_merge(['key' => null], $config);
}
/**
* Updates the request query with the developer key if auth is set to simple.
*
* use Google\Auth\Middleware\SimpleMiddleware;
* use GuzzleHttp\Client;
* use GuzzleHttp\HandlerStack;
*
* $my_key = 'is not the same as yours';
* $middleware = new SimpleMiddleware(['key' => $my_key]);
* $stack = HandlerStack::create();
* $stack->push($middleware);
*
* $client = new Client([
* 'handler' => $stack,
* 'base_uri' => 'https://www.googleapis.com/discovery/v1/',
* 'auth' => 'simple'
* ]);
*
* $res = $client->get('drive/v2/rest');
*
* @param callable $handler
* @return \Closure
*/
public function __invoke(callable $handler)
{
return function (\WPMailSMTP\Vendor\Psr\Http\Message\RequestInterface $request, array $options) use($handler) {
// Requests using "auth"="scoped" will be authorized.
if (!isset($options['auth']) || $options['auth'] !== 'simple') {
return $handler($request, $options);
}
$query = \WPMailSMTP\Vendor\GuzzleHttp\Psr7\parse_query($request->getUri()->getQuery());
$params = \array_merge($query, $this->config);
$uri = $request->getUri()->withQuery(\WPMailSMTP\Vendor\GuzzleHttp\Psr7\build_query($params));
$request = $request->withUri($uri);
return $handler($request, $options);
};
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,32 @@
<?php
/*
* Copyright 2020 Google LLC
*
* 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.
*/
namespace WPMailSMTP\Vendor\Google\Auth;
/**
* Describes a Credentials object which supports fetching the project ID.
*/
interface ProjectIdProviderInterface
{
/**
* Get the project ID.
*
* @param callable $httpHandler Callback which delivers psr7 request
* @return string|null
*/
public function getProjectId(callable $httpHandler = null);
}

View File

@ -0,0 +1,53 @@
<?php
/*
* Copyright 2019 Google LLC
*
* 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.
*/
namespace WPMailSMTP\Vendor\Google\Auth;
use WPMailSMTP\Vendor\phpseclib\Crypt\RSA;
/**
* Sign a string using a Service Account private key.
*/
trait ServiceAccountSignerTrait
{
/**
* Sign a string using the service account private key.
*
* @param string $stringToSign
* @param bool $forceOpenssl Whether to use OpenSSL regardless of
* whether phpseclib is installed. **Defaults to** `false`.
* @return string
*/
public function signBlob($stringToSign, $forceOpenssl = \false)
{
$privateKey = $this->auth->getSigningKey();
$signedString = '';
if (\class_exists('WPMailSMTP\\Vendor\\phpseclib\\Crypt\\RSA') && !$forceOpenssl) {
$rsa = new \WPMailSMTP\Vendor\phpseclib\Crypt\RSA();
$rsa->loadKey($privateKey);
$rsa->setSignatureMode(\WPMailSMTP\Vendor\phpseclib\Crypt\RSA::SIGNATURE_PKCS1);
$rsa->setHash('sha256');
$signedString = $rsa->sign($stringToSign);
} elseif (\extension_loaded('openssl')) {
\openssl_sign($stringToSign, $signedString, $privateKey, 'sha256WithRSAEncryption');
} else {
// @codeCoverageIgnoreStart
throw new \RuntimeException('OpenSSL is not installed.');
}
// @codeCoverageIgnoreEnd
return \base64_encode($signedString);
}
}

View File

@ -0,0 +1,43 @@
<?php
/*
* Copyright 2019 Google LLC
*
* 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.
*/
namespace WPMailSMTP\Vendor\Google\Auth;
/**
* Describes a class which supports signing arbitrary strings.
*/
interface SignBlobInterface extends \WPMailSMTP\Vendor\Google\Auth\FetchAuthTokenInterface
{
/**
* Sign a string using the method which is best for a given credentials type.
*
* @param string $stringToSign The string to sign.
* @param bool $forceOpenssl Require use of OpenSSL for local signing. Does
* not apply to signing done using external services. **Defaults to**
* `false`.
* @return string The resulting signature. Value should be base64-encoded.
*/
public function signBlob($stringToSign, $forceOpenssl = \false);
/**
* Returns the current Client Name.
*
* @param callable $httpHandler callback which delivers psr7 request, if
* one is required to obtain a client name.
* @return string
*/
public function getClientName(callable $httpHandler = null);
}

View File

@ -0,0 +1,120 @@
<?php
/*
* Copyright 2015 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.
*/
namespace WPMailSMTP\Vendor\Google\Auth\Subscriber;
use WPMailSMTP\Vendor\Google\Auth\FetchAuthTokenInterface;
use WPMailSMTP\Vendor\Google\Auth\GetQuotaProjectInterface;
use WPMailSMTP\Vendor\GuzzleHttp\Event\BeforeEvent;
use WPMailSMTP\Vendor\GuzzleHttp\Event\RequestEvents;
use WPMailSMTP\Vendor\GuzzleHttp\Event\SubscriberInterface;
/**
* AuthTokenSubscriber is a Guzzle Subscriber that adds an Authorization header
* provided by an object implementing FetchAuthTokenInterface.
*
* The FetchAuthTokenInterface#fetchAuthToken is used to obtain a hash; one of
* the values value in that hash is added as the authorization header.
*
* Requests will be accessed with the authorization header:
*
* 'authorization' 'Bearer <value of auth_token>'
*/
class AuthTokenSubscriber implements \WPMailSMTP\Vendor\GuzzleHttp\Event\SubscriberInterface
{
/**
* @var callable
*/
private $httpHandler;
/**
* @var FetchAuthTokenInterface
*/
private $fetcher;
/**
* @var callable
*/
private $tokenCallback;
/**
* Creates a new AuthTokenSubscriber.
*
* @param FetchAuthTokenInterface $fetcher is used to fetch the auth token
* @param callable $httpHandler (optional) http client to fetch the token.
* @param callable $tokenCallback (optional) function to be called when a new token is fetched.
*/
public function __construct(\WPMailSMTP\Vendor\Google\Auth\FetchAuthTokenInterface $fetcher, callable $httpHandler = null, callable $tokenCallback = null)
{
$this->fetcher = $fetcher;
$this->httpHandler = $httpHandler;
$this->tokenCallback = $tokenCallback;
}
/**
* @return array
*/
public function getEvents()
{
return ['before' => ['onBefore', \WPMailSMTP\Vendor\GuzzleHttp\Event\RequestEvents::SIGN_REQUEST]];
}
/**
* Updates the request with an Authorization header when auth is 'fetched_auth_token'.
*
* Example:
* ```
* use GuzzleHttp\Client;
* use Google\Auth\OAuth2;
* use Google\Auth\Subscriber\AuthTokenSubscriber;
*
* $config = [..<oauth config param>.];
* $oauth2 = new OAuth2($config)
* $subscriber = new AuthTokenSubscriber($oauth2);
*
* $client = new Client([
* 'base_url' => 'https://www.googleapis.com/taskqueue/v1beta2/projects/',
* 'defaults' => ['auth' => 'google_auth']
* ]);
* $client->getEmitter()->attach($subscriber);
*
* $res = $client->get('myproject/taskqueues/myqueue');
* ```
*
* @param BeforeEvent $event
*/
public function onBefore(\WPMailSMTP\Vendor\GuzzleHttp\Event\BeforeEvent $event)
{
// Requests using "auth"="google_auth" will be authorized.
$request = $event->getRequest();
if ($request->getConfig()['auth'] != 'google_auth') {
return;
}
// Fetch the auth token.
$auth_tokens = $this->fetcher->fetchAuthToken($this->httpHandler);
if (\array_key_exists('access_token', $auth_tokens)) {
$request->setHeader('authorization', 'Bearer ' . $auth_tokens['access_token']);
// notify the callback if applicable
if ($this->tokenCallback) {
\call_user_func($this->tokenCallback, $this->fetcher->getCacheKey(), $auth_tokens['access_token']);
}
}
if ($quotaProject = $this->getQuotaProject()) {
$request->setHeader(\WPMailSMTP\Vendor\Google\Auth\GetQuotaProjectInterface::X_GOOG_USER_PROJECT_HEADER, $quotaProject);
}
}
private function getQuotaProject()
{
if ($this->fetcher instanceof \WPMailSMTP\Vendor\Google\Auth\GetQuotaProjectInterface) {
return $this->fetcher->getQuotaProject();
}
}
}

View File

@ -0,0 +1,154 @@
<?php
/*
* Copyright 2015 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.
*/
namespace WPMailSMTP\Vendor\Google\Auth\Subscriber;
use WPMailSMTP\Vendor\Google\Auth\CacheTrait;
use WPMailSMTP\Vendor\GuzzleHttp\Event\BeforeEvent;
use WPMailSMTP\Vendor\GuzzleHttp\Event\RequestEvents;
use WPMailSMTP\Vendor\GuzzleHttp\Event\SubscriberInterface;
use WPMailSMTP\Vendor\Psr\Cache\CacheItemPoolInterface;
/**
* ScopedAccessTokenSubscriber is a Guzzle Subscriber that adds an Authorization
* header provided by a closure.
*
* The closure returns an access token, taking the scope, either a single
* string or an array of strings, as its value. If provided, a cache will be
* used to preserve the access token for a given lifetime.
*
* Requests will be accessed with the authorization header:
*
* 'authorization' 'Bearer <access token obtained from the closure>'
*/
class ScopedAccessTokenSubscriber implements \WPMailSMTP\Vendor\GuzzleHttp\Event\SubscriberInterface
{
use CacheTrait;
const DEFAULT_CACHE_LIFETIME = 1500;
/**
* @var CacheItemPoolInterface
*/
private $cache;
/**
* @var callable The access token generator function
*/
private $tokenFunc;
/**
* @var array|string The scopes used to generate the token
*/
private $scopes;
/**
* @var array
*/
private $cacheConfig;
/**
* Creates a new ScopedAccessTokenSubscriber.
*
* @param callable $tokenFunc a token generator function
* @param array|string $scopes the token authentication scopes
* @param array $cacheConfig configuration for the cache when it's present
* @param CacheItemPoolInterface $cache an implementation of CacheItemPoolInterface
*/
public function __construct(callable $tokenFunc, $scopes, array $cacheConfig = null, \WPMailSMTP\Vendor\Psr\Cache\CacheItemPoolInterface $cache = null)
{
$this->tokenFunc = $tokenFunc;
if (!(\is_string($scopes) || \is_array($scopes))) {
throw new \InvalidArgumentException('wants scope should be string or array');
}
$this->scopes = $scopes;
if (!\is_null($cache)) {
$this->cache = $cache;
$this->cacheConfig = \array_merge(['lifetime' => self::DEFAULT_CACHE_LIFETIME, 'prefix' => ''], $cacheConfig);
}
}
/**
* @return array
*/
public function getEvents()
{
return ['before' => ['onBefore', \WPMailSMTP\Vendor\GuzzleHttp\Event\RequestEvents::SIGN_REQUEST]];
}
/**
* Updates the request with an Authorization header when auth is 'scoped'.
*
* E.g this could be used to authenticate using the AppEngine AppIdentityService.
*
* Example:
* ```
* use google\appengine\api\app_identity\AppIdentityService;
* use Google\Auth\Subscriber\ScopedAccessTokenSubscriber;
* use GuzzleHttp\Client;
*
* $scope = 'https://www.googleapis.com/auth/taskqueue'
* $subscriber = new ScopedAccessToken(
* 'AppIdentityService::getAccessToken',
* $scope,
* ['prefix' => 'Google\Auth\ScopedAccessToken::'],
* $cache = new Memcache()
* );
*
* $client = new Client([
* 'base_url' => 'https://www.googleapis.com/taskqueue/v1beta2/projects/',
* 'defaults' => ['auth' => 'scoped']
* ]);
* $client->getEmitter()->attach($subscriber);
*
* $res = $client->get('myproject/taskqueues/myqueue');
* ```
*
* @param BeforeEvent $event
*/
public function onBefore(\WPMailSMTP\Vendor\GuzzleHttp\Event\BeforeEvent $event)
{
// Requests using "auth"="scoped" will be authorized.
$request = $event->getRequest();
if ($request->getConfig()['auth'] != 'scoped') {
return;
}
$auth_header = 'Bearer ' . $this->fetchToken();
$request->setHeader('authorization', $auth_header);
}
/**
* @return string
*/
private function getCacheKey()
{
$key = null;
if (\is_string($this->scopes)) {
$key .= $this->scopes;
} elseif (\is_array($this->scopes)) {
$key .= \implode(':', $this->scopes);
}
return $key;
}
/**
* Determine if token is available in the cache, if not call tokenFunc to
* fetch it.
*
* @return string
*/
private function fetchToken()
{
$cacheKey = $this->getCacheKey();
$cached = $this->getCachedValue($cacheKey);
if (!empty($cached)) {
return $cached;
}
$token = \call_user_func($this->tokenFunc, $this->scopes);
$this->setCachedValue($cacheKey, $token);
return $token;
}
}

View File

@ -0,0 +1,88 @@
<?php
/*
* Copyright 2015 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.
*/
namespace WPMailSMTP\Vendor\Google\Auth\Subscriber;
use WPMailSMTP\Vendor\GuzzleHttp\Event\BeforeEvent;
use WPMailSMTP\Vendor\GuzzleHttp\Event\RequestEvents;
use WPMailSMTP\Vendor\GuzzleHttp\Event\SubscriberInterface;
/**
* SimpleSubscriber is a Guzzle Subscriber that implements Google's Simple API
* access.
*
* Requests are accessed using the Simple API access developer key.
*/
class SimpleSubscriber implements \WPMailSMTP\Vendor\GuzzleHttp\Event\SubscriberInterface
{
/**
* @var array
*/
private $config;
/**
* Create a new Simple plugin.
*
* The configuration array expects one option
* - key: required, otherwise InvalidArgumentException is thrown
*
* @param array $config Configuration array
*/
public function __construct(array $config)
{
if (!isset($config['key'])) {
throw new \InvalidArgumentException('requires a key to have been set');
}
$this->config = \array_merge([], $config);
}
/**
* @return array
*/
public function getEvents()
{
return ['before' => ['onBefore', \WPMailSMTP\Vendor\GuzzleHttp\Event\RequestEvents::SIGN_REQUEST]];
}
/**
* Updates the request query with the developer key if auth is set to simple.
*
* Example:
* ```
* use Google\Auth\Subscriber\SimpleSubscriber;
* use GuzzleHttp\Client;
*
* $my_key = 'is not the same as yours';
* $subscriber = new SimpleSubscriber(['key' => $my_key]);
*
* $client = new Client([
* 'base_url' => 'https://www.googleapis.com/discovery/v1/',
* 'defaults' => ['auth' => 'simple']
* ]);
* $client->getEmitter()->attach($subscriber);
*
* $res = $client->get('drive/v2/rest');
* ```
*
* @param BeforeEvent $event
*/
public function onBefore(\WPMailSMTP\Vendor\GuzzleHttp\Event\BeforeEvent $event)
{
// Requests using "auth"="simple" with the developer key.
$request = $event->getRequest();
if ($request->getConfig()['auth'] != 'simple') {
return;
}
$request->getQuery()->overwriteWith($this->config);
}
}

View File

@ -0,0 +1,36 @@
<?php
/*
* Copyright 2020 Google LLC
*
* 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.
*/
namespace WPMailSMTP\Vendor\Google\Auth;
/**
* Describes a Credentials object which supports updating request metadata
* (request headers).
*/
interface UpdateMetadataInterface
{
const AUTH_METADATA_KEY = 'authorization';
/**
* Updates metadata with the authorization token.
*
* @param array $metadata metadata hashmap
* @param string $authUri optional auth uri
* @param callable $httpHandler callback which delivers psr7 request
* @return array updated metadata hashmap
*/
public function updateMetadata($metadata, $authUri = null, callable $httpHandler = null);
}