updated plugin WP Mail SMTP version 2.5.0

This commit is contained in:
2020-10-23 01:19:42 +00:00
committed by Gitium
parent 1047e0b29f
commit 51360a4729
205 changed files with 36345 additions and 921 deletions

View File

@ -119,7 +119,7 @@ class ApplicationDefaultCredentials
* 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
* @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
@ -127,14 +127,18 @@ class ApplicationDefaultCredentials
* provided if you have one already available for use.
* @param string $quotaProject specifies a project to bill for access
* charges associated with the request.
* @param string|array $defaultScope The default scope to use if no
* user-defined scopes exist, expressed either as an Array or as a
* space-delimited string.
*
* @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)
public static function getCredentials($scope = null, callable $httpHandler = null, array $cacheConfig = null, \WPMailSMTP\Vendor\Psr\Cache\CacheItemPoolInterface $cache = null, $quotaProject = null, $defaultScope = null)
{
$creds = null;
$jsonKey = \WPMailSMTP\Vendor\Google\Auth\CredentialsLoader::fromEnv() ?: \WPMailSMTP\Vendor\Google\Auth\CredentialsLoader::fromWellKnownFile();
$anyScope = $scope ?: $defaultScope;
if (!$httpHandler) {
if (!($client = \WPMailSMTP\Vendor\Google\Auth\HttpHandler\HttpClientCache::getHttpClient())) {
$client = new \WPMailSMTP\Vendor\GuzzleHttp\Client();
@ -146,11 +150,11 @@ class ApplicationDefaultCredentials
if ($quotaProject) {
$jsonKey['quota_project_id'] = $quotaProject;
}
$creds = \WPMailSMTP\Vendor\Google\Auth\CredentialsLoader::makeCredentials($scope, $jsonKey);
$creds = \WPMailSMTP\Vendor\Google\Auth\CredentialsLoader::makeCredentials($scope, $jsonKey, $defaultScope);
} elseif (\WPMailSMTP\Vendor\Google\Auth\Credentials\AppIdentityCredentials::onAppEngine() && !\WPMailSMTP\Vendor\Google\Auth\Credentials\GCECredentials::onAppEngineFlexible()) {
$creds = new \WPMailSMTP\Vendor\Google\Auth\Credentials\AppIdentityCredentials($scope);
$creds = new \WPMailSMTP\Vendor\Google\Auth\Credentials\AppIdentityCredentials($anyScope);
} elseif (self::onGce($httpHandler, $cacheConfig, $cache)) {
$creds = new \WPMailSMTP\Vendor\Google\Auth\Credentials\GCECredentials(null, $scope, null, $quotaProject);
$creds = new \WPMailSMTP\Vendor\Google\Auth\Credentials\GCECredentials(null, $anyScope, null, $quotaProject);
}
if (\is_null($creds)) {
throw new \DomainException(self::notFound());

View File

@ -138,6 +138,10 @@ class GCECredentials extends \WPMailSMTP\Vendor\Google\Auth\CredentialsLoader im
* @var string|null
*/
private $quotaProject;
/**
* @var string|null
*/
private $serviceAccountIdentity;
/**
* @param Iam $iam [optional] An IAM instance.
* @param string|array $scope [optional] the scope of the access request,
@ -145,14 +149,16 @@ class GCECredentials extends \WPMailSMTP\Vendor\Google\Auth\CredentialsLoader im
* @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.
* @param string $serviceAccountIdentity [optional] Specify a service
* account identity name to use instead of "default".
*/
public function __construct(\WPMailSMTP\Vendor\Google\Auth\Iam $iam = null, $scope = null, $targetAudience = null, $quotaProject = null)
public function __construct(\WPMailSMTP\Vendor\Google\Auth\Iam $iam = null, $scope = null, $targetAudience = null, $quotaProject = null, $serviceAccountIdentity = null)
{
$this->iam = $iam;
if ($scope && $targetAudience) {
throw new \InvalidArgumentException('Scope and targetAudience cannot both be supplied');
}
$tokenUri = self::getTokenUri();
$tokenUri = self::getTokenUri($serviceAccountIdentity);
if ($scope) {
if (\is_string($scope)) {
$scope = \explode(' ', $scope);
@ -160,31 +166,61 @@ class GCECredentials extends \WPMailSMTP\Vendor\Google\Auth\CredentialsLoader im
$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);
$tokenUri = self::getIdTokenUri($serviceAccountIdentity);
$tokenUri = $tokenUri . '?audience=' . $targetAudience;
$this->targetAudience = $targetAudience;
}
$this->tokenUri = $tokenUri;
$this->quotaProject = $quotaProject;
$this->serviceAccountIdentity = $serviceAccountIdentity;
}
/**
* The full uri for accessing the default token.
*
* @param string $serviceAccountIdentity [optional] Specify a service
* account identity name to use instead of "default".
* @return string
*/
public static function getTokenUri()
public static function getTokenUri($serviceAccountIdentity = null)
{
$base = 'http://' . self::METADATA_IP . '/computeMetadata/';
return $base . self::TOKEN_URI_PATH;
$base .= self::TOKEN_URI_PATH;
if ($serviceAccountIdentity) {
return \str_replace('/default/', '/' . $serviceAccountIdentity . '/', $base);
}
return $base;
}
/**
* The full uri for accessing the default service account.
*
* @param string $serviceAccountIdentity [optional] Specify a service
* account identity name to use instead of "default".
* @return string
*/
public static function getClientNameUri()
public static function getClientNameUri($serviceAccountIdentity = null)
{
$base = 'http://' . self::METADATA_IP . '/computeMetadata/';
return $base . self::CLIENT_ID_URI_PATH;
$base .= self::CLIENT_ID_URI_PATH;
if ($serviceAccountIdentity) {
return \str_replace('/default/', '/' . $serviceAccountIdentity . '/', $base);
}
return $base;
}
/**
* The full uri for accesesing the default identity token.
*
* @param string $serviceAccountIdentity [optional] Specify a service
* account identity name to use instead of "default".
* @return string
*/
private static function getIdTokenUri($serviceAccountIdentity = null)
{
$base = 'http://' . self::METADATA_IP . '/computeMetadata/';
$base .= self::ID_TOKEN_URI_PATH;
if ($serviceAccountIdentity) {
return \str_replace('/default/', '/' . $serviceAccountIdentity . '/', $base);
}
return $base;
}
/**
* The full uri for accessing the default project ID.
@ -275,9 +311,9 @@ class GCECredentials extends \WPMailSMTP\Vendor\Google\Auth\CredentialsLoader im
if (null === ($json = \json_decode($response, \true))) {
throw new \Exception('Invalid JSON response');
}
$json['expires_at'] = \time() + $json['expires_in'];
// store this so we can retrieve it later
$this->lastReceivedToken = $json;
$this->lastReceivedToken['expires_at'] = \time() + $json['expires_in'];
return $json;
}
/**
@ -318,7 +354,7 @@ class GCECredentials extends \WPMailSMTP\Vendor\Google\Auth\CredentialsLoader im
if (!$this->isOnGce) {
return '';
}
$this->clientName = $this->getFromMetadata($httpHandler, self::getClientNameUri());
$this->clientName = $this->getFromMetadata($httpHandler, self::getClientNameUri($this->serviceAccountIdentity));
return $this->clientName;
}
/**

View File

@ -76,6 +76,10 @@ class ServiceAccountCredentials extends \WPMailSMTP\Vendor\Google\Auth\Credentia
* @var string|null
*/
protected $projectId;
/*
* @var array|null
*/
private $lastReceivedJwtAccessToken;
/**
* Create a new ServiceAccountCredentials.
*
@ -146,7 +150,9 @@ class ServiceAccountCredentials extends \WPMailSMTP\Vendor\Google\Auth\Credentia
*/
public function getLastReceivedToken()
{
return $this->auth->getLastReceivedToken();
// If self-signed JWTs are being used, fetch the last received token
// from memory. Else, fetch it from OAuth2
return $this->useSelfSignedJwt() ? $this->lastReceivedJwtAccessToken : $this->auth->getLastReceivedToken();
}
/**
* Get the project ID from the service account keyfile.
@ -171,14 +177,18 @@ class ServiceAccountCredentials extends \WPMailSMTP\Vendor\Google\Auth\Credentia
public function updateMetadata($metadata, $authUri = null, callable $httpHandler = null)
{
// scope exists. use oauth implementation
$scope = $this->auth->getScope();
if (!\is_null($scope)) {
if (!$this->useSelfSignedJwt()) {
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);
$updatedMetadata = $jwtCreds->updateMetadata($metadata, $authUri, $httpHandler);
if ($lastReceivedToken = $jwtCreds->getLastReceivedToken()) {
// Keep self-signed JWTs in memory as the last received token
$this->lastReceivedJwtAccessToken = $lastReceivedToken;
}
return $updatedMetadata;
}
/**
* @param string $sub an email address account to impersonate, in situations when
@ -209,4 +219,8 @@ class ServiceAccountCredentials extends \WPMailSMTP\Vendor\Google\Auth\Credentia
{
return $this->quotaProject;
}
private function useSelfSignedJwt()
{
return \is_null($this->auth->getScope());
}
}

View File

@ -106,6 +106,8 @@ class ServiceAccountJwtAccessCredentials extends \WPMailSMTP\Vendor\Google\Auth\
return null;
}
$access_token = $this->auth->toJwt();
// Set the self-signed access token in OAuth2 for getLastReceivedToken
$this->auth->setAccessToken($access_token);
return array('access_token' => $access_token);
}
/**

View File

@ -119,18 +119,24 @@ abstract class CredentialsLoader implements \WPMailSMTP\Vendor\Google\Auth\Fetch
* @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.
* @param string|array $defaultScope The default scope to use if no
* user-defined scopes exist, expressed either as an Array or as a
* space-delimited string.
*
* @return ServiceAccountCredentials|UserRefreshCredentials
*/
public static function makeCredentials($scope, array $jsonKey)
public static function makeCredentials($scope, array $jsonKey, $defaultScope = null)
{
if (!\array_key_exists('type', $jsonKey)) {
throw new \InvalidArgumentException('json key is missing the type field');
}
if ($jsonKey['type'] == 'service_account') {
// Do not pass $defaultScope to ServiceAccountCredentials
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);
$anyScope = $scope ?: $defaultScope;
return new \WPMailSMTP\Vendor\Google\Auth\Credentials\UserRefreshCredentials($anyScope, $jsonKey);
}
throw new \InvalidArgumentException('invalid value in the type field');
}
@ -188,7 +194,7 @@ abstract class CredentialsLoader implements \WPMailSMTP\Vendor\Google\Auth\Fetch
{
if (isset($metadata[self::AUTH_METADATA_KEY])) {
// Auth metadata has already been set
return $metdadata;
return $metadata;
}
$result = $this->fetchAuthToken($httpHandler);
if (!isset($result['access_token'])) {

View File

@ -60,29 +60,11 @@ class FetchAuthTokenCache implements \WPMailSMTP\Vendor\Google\Auth\FetchAuthTok
*/
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;
}
if ($cached = $this->fetchAuthTokenFromCache()) {
return $cached;
}
$auth_token = $this->fetcher->fetchAuthToken($httpHandler);
if (isset($auth_token['access_token']) || isset($auth_token['id_token'])) {
$this->setCachedValue($cacheKey, $auth_token);
}
$this->saveAuthTokenInCache($auth_token);
return $auth_token;
}
/**
@ -169,12 +151,51 @@ class FetchAuthTokenCache implements \WPMailSMTP\Vendor\Google\Auth\FetchAuthTok
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']];
$cached = $this->fetchAuthTokenFromCache($authUri);
if ($cached) {
// Set the access token in the `Authorization` metadata header so
// the downstream call to updateMetadata know they don't need to
// fetch another token.
if (isset($cached['access_token'])) {
$metadata[self::AUTH_METADATA_KEY] = ['Bearer ' . $cached['access_token']];
}
}
$newMetadata = $this->fetcher->updateMetadata($metadata, $authUri, $httpHandler);
if (!$cached && ($token = $this->fetcher->getLastReceivedToken())) {
$this->saveAuthTokenInCache($token, $authUri);
}
return $newMetadata;
}
private function fetchAuthTokenFromCache($authUri = 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.
// if $authUri is set, use it as the cache key
$cacheKey = $authUri ? $this->getFullCacheKey($authUri) : $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;
}
}
return null;
}
private function saveAuthTokenInCache($authToken, $authUri = null)
{
if (isset($authToken['access_token']) || isset($authToken['id_token'])) {
// if $authUri is set, use it as the cache key
$cacheKey = $authUri ? $this->getFullCacheKey($authUri) : $this->fetcher->getCacheKey();
$this->setCachedValue($cacheKey, $authToken);
}
return $this->fetcher->updateMetadata($metadata, $authUri, $httpHandler);
}
}

View File

@ -1096,14 +1096,28 @@ class OAuth2 implements \WPMailSMTP\Vendor\Google\Auth\FetchAuthTokenInterface
/**
* The expiration of the last received token.
*
* @return array
* @return array|null
*/
public function getLastReceivedToken()
{
if ($token = $this->getAccessToken()) {
return ['access_token' => $token, 'expires_at' => $this->getExpiresAt()];
// the bare necessity of an auth token
$authToken = ['access_token' => $token, 'expires_at' => $this->getExpiresAt()];
} elseif ($idToken = $this->getIdToken()) {
$authToken = ['id_token' => $idToken, 'expires_at' => $this->getExpiresAt()];
} else {
return null;
}
return null;
if ($expiresIn = $this->getExpiresIn()) {
$authToken['expires_in'] = $expiresIn;
}
if ($issuedAt = $this->getIssuedAt()) {
$authToken['issued_at'] = $issuedAt;
}
if ($refreshToken = $this->getRefreshToken()) {
$authToken['refresh_token'] = $refreshToken;
}
return $authToken;
}
/**
* Get the client ID.