PluginProbe
Media Cloud Sync / 1.2.11
Media Cloud Sync v1.2.11
1.4.2 1.4.1 1.4.0 1.3.12 1.3.11 1.3.10 trunk 1.0.0 1.0.1 1.0.2 1.0.3 1.1.0 1.1.1 1.2.0 1.2.10 1.2.11 1.2.12 1.2.13 1.2.2 1.2.3 1.2.4 1.2.5 1.2.6 1.2.7 1.2.8 All 36 releases
media-cloud-sync / includes / sdk / google / google / gax / src / CredentialsWrapper.php

CredentialsWrapper.php in Media Cloud Sync 1.2.11, at includes/sdk/google/google/gax/src/CredentialsWrapper.php

278 lines 13.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /*
4 * Copyright 2018 Google LLC
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are
9 * met:
10 *
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * * Redistributions in binary form must reproduce the above
14 * copyright notice, this list of conditions and the following disclaimer
15 * in the documentation and/or other materials provided with the
16 * distribution.
17 * * Neither the name of Google Inc. nor the names of its
18 * contributors may be used to endorse or promote products derived from
19 * this software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */
33 namespace Dudlewebs\WPMCS\Google\ApiCore;
34
35 use DomainException;
36 use Exception;
37 use Dudlewebs\WPMCS\Google\Auth\ApplicationDefaultCredentials;
38 use Dudlewebs\WPMCS\Google\Auth\ProjectIdProviderInterface;
39 use Dudlewebs\WPMCS\Google\Auth\Cache\MemoryCacheItemPool;
40 use Dudlewebs\WPMCS\Google\Auth\Credentials\ServiceAccountCredentials;
41 use Dudlewebs\WPMCS\Google\Auth\CredentialsLoader;
42 use Dudlewebs\WPMCS\Google\Auth\FetchAuthTokenCache;
43 use Dudlewebs\WPMCS\Google\Auth\FetchAuthTokenInterface;
44 use Dudlewebs\WPMCS\Google\Auth\GetQuotaProjectInterface;
45 use Dudlewebs\WPMCS\Google\Auth\GetUniverseDomainInterface;
46 use Dudlewebs\WPMCS\Google\Auth\HttpHandler\Guzzle6HttpHandler;
47 use Dudlewebs\WPMCS\Google\Auth\HttpHandler\Guzzle7HttpHandler;
48 use Dudlewebs\WPMCS\Google\Auth\HttpHandler\HttpHandlerFactory;
49 use Dudlewebs\WPMCS\Google\Auth\UpdateMetadataInterface;
50 use Dudlewebs\WPMCS\Psr\Cache\CacheItemPoolInterface;
51 /**
52 * The CredentialsWrapper object provides a wrapper around a FetchAuthTokenInterface.
53 */
54 class CredentialsWrapper implements ProjectIdProviderInterface
55 {
56 use ValidationTrait;
57 /** @var FetchAuthTokenInterface $credentialsFetcher */
58 private ?FetchAuthTokenInterface $credentialsFetcher = null;
59 /** @var callable $authHttpHandle */
60 private $authHttpHandler;
61 private string $universeDomain;
62 private bool $hasCheckedUniverse = \false;
63 /** @var int */
64 private static int $eagerRefreshThresholdSeconds = 10;
65 /**
66 * CredentialsWrapper constructor.
67 * @param FetchAuthTokenInterface $credentialsFetcher A credentials loader
68 * used to fetch access tokens.
69 * @param callable $authHttpHandler A handler used to deliver PSR-7 requests
70 * specifically for authentication. Should match a signature of
71 * `function (RequestInterface $request, array $options) : ResponseInterface`.
72 * @throws ValidationException
73 */
74 public function __construct(FetchAuthTokenInterface $credentialsFetcher, callable $authHttpHandler = null, string $universeDomain = GetUniverseDomainInterface::DEFAULT_UNIVERSE_DOMAIN)
75 {
76 $this->credentialsFetcher = $credentialsFetcher;
77 $this->authHttpHandler = $authHttpHandler ?: self::buildHttpHandlerFactory();
78 if (empty($universeDomain)) {
79 throw new ValidationException('The universe domain cannot be empty');
80 }
81 $this->universeDomain = $universeDomain;
82 }
83 /**
84 * Factory method to create a CredentialsWrapper from an array of options.
85 *
86 * @param array $args {
87 * An array of optional arguments.
88 *
89 * @type string|array $keyFile
90 * Credentials to be used. Accepts either a path to a credentials file, or a decoded
91 * credentials file as a PHP array. If this is not specified, application default
92 * credentials will be used.
93 * @type string[] $scopes
94 * A string array of scopes to use when acquiring credentials.
95 * @type callable $authHttpHandler
96 * A handler used to deliver PSR-7 requests specifically
97 * for authentication. Should match a signature of
98 * `function (RequestInterface $request, array $options) : ResponseInterface`.
99 * @type bool $enableCaching
100 * Enable caching of access tokens. Defaults to true.
101 * @type CacheItemPoolInterface $authCache
102 * A cache for storing access tokens. Defaults to a simple in memory implementation.
103 * @type array $authCacheOptions
104 * Cache configuration options.
105 * @type string $quotaProject
106 * Specifies a user project to bill for access charges associated with the request.
107 * @type string[] $defaultScopes
108 * A string array of default scopes to use when acquiring
109 * credentials.
110 * @type bool $useJwtAccessWithScope
111 * Ensures service account credentials use JWT Access (also known as self-signed
112 * JWTs), even when user-defined scopes are supplied.
113 * }
114 * @param string $universeDomain The expected universe of the credentials. Defaults to
115 * "googleapis.com"
116 * @return CredentialsWrapper
117 * @throws ValidationException
118 */
119 public static function build(array $args = [], string $universeDomain = GetUniverseDomainInterface::DEFAULT_UNIVERSE_DOMAIN)
120 {
121 $args += ['keyFile' => null, 'scopes' => null, 'authHttpHandler' => null, 'enableCaching' => \true, 'authCache' => null, 'authCacheOptions' => [], 'quotaProject' => null, 'defaultScopes' => null, 'useJwtAccessWithScope' => \true];
122 $keyFile = $args['keyFile'];
123 $authHttpHandler = $args['authHttpHandler'] ?: self::buildHttpHandlerFactory();
124 if (is_null($keyFile)) {
125 $loader = self::buildApplicationDefaultCredentials($args['scopes'], $authHttpHandler, $args['authCacheOptions'], $args['authCache'], $args['quotaProject'], $args['defaultScopes']);
126 if ($loader instanceof FetchAuthTokenCache) {
127 $loader = $loader->getFetcher();
128 }
129 } else {
130 if (is_string($keyFile)) {
131 if (!file_exists($keyFile)) {
132 throw new ValidationException("Could not find keyfile: {$keyFile}");
133 }
134 $keyFile = json_decode(file_get_contents($keyFile), \true);
135 }
136 if (isset($args['quotaProject'])) {
137 $keyFile['quota_project_id'] = $args['quotaProject'];
138 }
139 $loader = CredentialsLoader::makeCredentials($args['scopes'], $keyFile, $args['defaultScopes']);
140 }
141 if ($loader instanceof ServiceAccountCredentials && $args['useJwtAccessWithScope']) {
142 // Ensures the ServiceAccountCredentials uses JWT Access, also known
143 // as self-signed JWTs, even when user-defined scopes are supplied.
144 $loader->useJwtAccessWithScope();
145 }
146 if ($args['enableCaching']) {
147 $authCache = $args['authCache'] ?: new MemoryCacheItemPool();
148 $loader = new FetchAuthTokenCache($loader, $args['authCacheOptions'], $authCache);
149 }
150 return new CredentialsWrapper($loader, $authHttpHandler, $universeDomain);
151 }
152 /**
153 * @return string|null The quota project associated with the credentials.
154 */
155 public function getQuotaProject()
156 {
157 if ($this->credentialsFetcher instanceof GetQuotaProjectInterface) {
158 return $this->credentialsFetcher->getQuotaProject();
159 }
160 return null;
161 }
162 public function getProjectId(callable $httpHandler = null): ?string
163 {
164 // Ensure that FetchAuthTokenCache does not throw an exception
165 if ($this->credentialsFetcher instanceof FetchAuthTokenCache && !$this->credentialsFetcher->getFetcher() instanceof ProjectIdProviderInterface) {
166 return null;
167 }
168 if ($this->credentialsFetcher instanceof ProjectIdProviderInterface) {
169 return $this->credentialsFetcher->getProjectId($httpHandler);
170 }
171 return null;
172 }
173 /**
174 * @deprecated
175 * @return string Bearer string containing access token.
176 */
177 public function getBearerString()
178 {
179 $token = $this->credentialsFetcher->getLastReceivedToken();
180 if (self::isExpired($token)) {
181 $this->checkUniverseDomain();
182 $token = $this->credentialsFetcher->fetchAuthToken($this->authHttpHandler);
183 if (!self::isValid($token)) {
184 return '';
185 }
186 }
187 return empty($token['access_token']) ? '' : 'Bearer ' . $token['access_token'];
188 }
189 /**
190 * @param string $audience optional audience for self-signed JWTs.
191 * @return callable Callable function that returns an authorization header.
192 */
193 public function getAuthorizationHeaderCallback($audience = null)
194 {
195 // NOTE: changes to this function should be treated carefully and tested thoroughly. It will
196 // be passed into the gRPC c extension, and changes have the potential to trigger very
197 // difficult-to-diagnose segmentation faults.
198 return function () use ($audience) {
199 $token = $this->credentialsFetcher->getLastReceivedToken();
200 if (self::isExpired($token)) {
201 $this->checkUniverseDomain();
202 // Call updateMetadata to take advantage of self-signed JWTs
203 if ($this->credentialsFetcher instanceof UpdateMetadataInterface) {
204 return $this->credentialsFetcher->updateMetadata([], $audience);
205 }
206 // In case a custom fetcher is provided (unlikely) which doesn't
207 // implement UpdateMetadataInterface
208 $token = $this->credentialsFetcher->fetchAuthToken($this->authHttpHandler);
209 if (!self::isValid($token)) {
210 return [];
211 }
212 }
213 $tokenString = $token['access_token'];
214 if (!empty($tokenString)) {
215 return ['authorization' => ["Bearer {$tokenString}"]];
216 }
217 return [];
218 };
219 }
220 /**
221 * Verify that the expected universe domain matches the universe domain from the credentials.
222 */
223 public function checkUniverseDomain()
224 {
225 if (\false === $this->hasCheckedUniverse) {
226 $credentialsUniverse = $this->credentialsFetcher instanceof GetUniverseDomainInterface ? $this->credentialsFetcher->getUniverseDomain() : GetUniverseDomainInterface::DEFAULT_UNIVERSE_DOMAIN;
227 if ($credentialsUniverse !== $this->universeDomain) {
228 throw new ValidationException(sprintf('The configured universe domain (%s) does not match the credential universe domain (%s)', $this->universeDomain, $credentialsUniverse));
229 }
230 $this->hasCheckedUniverse = \true;
231 }
232 }
233 /**
234 * @return Guzzle6HttpHandler|Guzzle7HttpHandler
235 * @throws ValidationException
236 */
237 private static function buildHttpHandlerFactory()
238 {
239 try {
240 return HttpHandlerFactory::build();
241 } catch (Exception $ex) {
242 throw new ValidationException("Failed to build HttpHandler", $ex->getCode(), $ex);
243 }
244 }
245 /**
246 * @param array $scopes
247 * @param callable $authHttpHandler
248 * @param array $authCacheOptions
249 * @param CacheItemPoolInterface $authCache
250 * @param string $quotaProject
251 * @param array $defaultScopes
252 * @return FetchAuthTokenInterface
253 * @throws ValidationException
254 */
255 private static function buildApplicationDefaultCredentials(array $scopes = null, callable $authHttpHandler = null, array $authCacheOptions = null, CacheItemPoolInterface $authCache = null, $quotaProject = null, array $defaultScopes = null)
256 {
257 try {
258 return ApplicationDefaultCredentials::getCredentials($scopes, $authHttpHandler, $authCacheOptions, $authCache, $quotaProject, $defaultScopes);
259 } catch (DomainException $ex) {
260 throw new ValidationException("Could not construct ApplicationDefaultCredentials", $ex->getCode(), $ex);
261 }
262 }
263 /**
264 * @param mixed $token
265 */
266 private static function isValid($token)
267 {
268 return is_array($token) && array_key_exists('access_token', $token);
269 }
270 /**
271 * @param mixed $token
272 */
273 private static function isExpired($token)
274 {
275 return !(self::isValid($token) && array_key_exists('expires_at', $token) && $token['expires_at'] > time() + self::$eagerRefreshThresholdSeconds);
276 }
277 }
278