PluginProbe
Authorizer / 3.15.0
Authorizer v3.15.0
3.15.3 3.15.2 3.15.1 3.15.0 3.14.3 3.14.4 3.14.2 3.14.1 2.8.1 2.8.2 2.8.3 2.8.4 2.8.5 2.8.6 2.8.7 2.8.8 2.9.0 2.9.1 2.9.10 2.9.11 2.9.12 2.9.13 2.9.2 2.9.3 2.9.6 All 126 releases
authorizer / vendor / google / auth / src / FetchAuthTokenCache.php

FetchAuthTokenCache.php in Authorizer 3.15.0, at vendor/google/auth/src/FetchAuthTokenCache.php

340 lines 10.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /*
3 * Copyright 2010 Google Inc.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18 namespace Google\Auth;
19
20 use Psr\Cache\CacheItemPoolInterface;
21
22 /**
23 * A class to implement caching for any object implementing
24 * FetchAuthTokenInterface
25 */
26 class FetchAuthTokenCache implements
27 FetchAuthTokenInterface,
28 GetQuotaProjectInterface,
29 GetUniverseDomainInterface,
30 SignBlobInterface,
31 ProjectIdProviderInterface,
32 UpdateMetadataInterface
33 {
34 use CacheTrait;
35
36 /**
37 * @var FetchAuthTokenInterface
38 */
39 private $fetcher;
40
41 /**
42 * @var int
43 */
44 private $eagerRefreshThresholdSeconds = 10;
45
46 /**
47 * @param FetchAuthTokenInterface $fetcher A credentials fetcher
48 * @param array<mixed>|null $cacheConfig Configuration for the cache
49 * @param CacheItemPoolInterface $cache
50 */
51 public function __construct(
52 FetchAuthTokenInterface $fetcher,
53 ?array $cacheConfig = null,
54 ?CacheItemPoolInterface $cache = null
55 ) {
56 $this->fetcher = $fetcher;
57 $this->cache = $cache;
58 $this->cacheConfig = array_merge([
59 'lifetime' => 1500,
60 'prefix' => '',
61 'cacheUniverseDomain' => $fetcher instanceof Credentials\GCECredentials,
62 ], (array) $cacheConfig);
63 }
64
65 /**
66 * @return FetchAuthTokenInterface
67 */
68 public function getFetcher()
69 {
70 return $this->fetcher;
71 }
72
73 /**
74 * Implements FetchAuthTokenInterface#fetchAuthToken.
75 *
76 * Checks the cache for a valid auth token and fetches the auth tokens
77 * from the supplied fetcher.
78 *
79 * @param callable|null $httpHandler callback which delivers psr7 request
80 * @return array<mixed> the response
81 * @throws \Exception
82 */
83 public function fetchAuthToken(?callable $httpHandler = null)
84 {
85 if ($cached = $this->fetchAuthTokenFromCache()) {
86 return $cached;
87 }
88
89 $auth_token = $this->fetcher->fetchAuthToken($httpHandler);
90
91 $this->saveAuthTokenInCache($auth_token);
92
93 return $auth_token;
94 }
95
96 /**
97 * @return string
98 */
99 public function getCacheKey()
100 {
101 return $this->getFullCacheKey($this->fetcher->getCacheKey());
102 }
103
104 /**
105 * @return array<mixed>|null
106 */
107 public function getLastReceivedToken()
108 {
109 return $this->fetcher->getLastReceivedToken();
110 }
111
112 /**
113 * Get the client name from the fetcher.
114 *
115 * @param callable|null $httpHandler An HTTP handler to deliver PSR7 requests.
116 * @return string
117 */
118 public function getClientName(?callable $httpHandler = null)
119 {
120 if (!$this->fetcher instanceof SignBlobInterface) {
121 throw new \RuntimeException(
122 'Credentials fetcher does not implement ' .
123 'Google\Auth\SignBlobInterface'
124 );
125 }
126
127 return $this->fetcher->getClientName($httpHandler);
128 }
129
130 /**
131 * Sign a blob using the fetcher.
132 *
133 * @param string $stringToSign The string to sign.
134 * @param bool $forceOpenSsl Require use of OpenSSL for local signing. Does
135 * not apply to signing done using external services. **Defaults to**
136 * `false`.
137 * @return string The resulting signature.
138 * @throws \RuntimeException If the fetcher does not implement
139 * `Google\Auth\SignBlobInterface`.
140 */
141 public function signBlob($stringToSign, $forceOpenSsl = false)
142 {
143 if (!$this->fetcher instanceof SignBlobInterface) {
144 throw new \RuntimeException(
145 'Credentials fetcher does not implement ' .
146 'Google\Auth\SignBlobInterface'
147 );
148 }
149
150 // Pass the access token from cache for credentials that sign blobs
151 // using the IAM API. This saves a call to fetch an access token when a
152 // cached token exists.
153 if ($this->fetcher instanceof Credentials\GCECredentials
154 || $this->fetcher instanceof Credentials\ImpersonatedServiceAccountCredentials
155 ) {
156 $cached = $this->fetchAuthTokenFromCache();
157 $accessToken = $cached['access_token'] ?? null;
158 return $this->fetcher->signBlob($stringToSign, $forceOpenSsl, $accessToken);
159 }
160
161 return $this->fetcher->signBlob($stringToSign, $forceOpenSsl);
162 }
163
164 /**
165 * Get the quota project used for this API request from the credentials
166 * fetcher.
167 *
168 * @return string|null
169 */
170 public function getQuotaProject()
171 {
172 if ($this->fetcher instanceof GetQuotaProjectInterface) {
173 return $this->fetcher->getQuotaProject();
174 }
175
176 return null;
177 }
178
179 /**
180 * Get the Project ID from the fetcher.
181 *
182 * @param callable|null $httpHandler Callback which delivers psr7 request
183 * @return string|null
184 * @throws \RuntimeException If the fetcher does not implement
185 * `Google\Auth\ProvidesProjectIdInterface`.
186 */
187 public function getProjectId(?callable $httpHandler = null)
188 {
189 if (!$this->fetcher instanceof ProjectIdProviderInterface) {
190 throw new \RuntimeException(
191 'Credentials fetcher does not implement ' .
192 'Google\Auth\ProvidesProjectIdInterface'
193 );
194 }
195
196 // Pass the access token from cache for credentials that require an
197 // access token to fetch the project ID. This saves a call to fetch an
198 // access token when a cached token exists.
199 if ($this->fetcher instanceof Credentials\ExternalAccountCredentials) {
200 $cached = $this->fetchAuthTokenFromCache();
201 $accessToken = $cached['access_token'] ?? null;
202 return $this->fetcher->getProjectId($httpHandler, $accessToken);
203 }
204
205 return $this->fetcher->getProjectId($httpHandler);
206 }
207
208 /*
209 * Get the Universe Domain from the fetcher.
210 *
211 * @return string
212 */
213 public function getUniverseDomain(): string
214 {
215 if ($this->fetcher instanceof GetUniverseDomainInterface) {
216 if ($this->cacheConfig['cacheUniverseDomain']) {
217 return $this->getCachedUniverseDomain($this->fetcher);
218 }
219 return $this->fetcher->getUniverseDomain();
220 }
221
222 return GetUniverseDomainInterface::DEFAULT_UNIVERSE_DOMAIN;
223 }
224
225 /**
226 * Updates metadata with the authorization token.
227 *
228 * @param array<mixed> $metadata metadata hashmap
229 * @param string $authUri optional auth uri
230 * @param callable|null $httpHandler callback which delivers psr7 request
231 * @return array<mixed> updated metadata hashmap
232 * @throws \RuntimeException If the fetcher does not implement
233 * `Google\Auth\UpdateMetadataInterface`.
234 */
235 public function updateMetadata(
236 $metadata,
237 $authUri = null,
238 ?callable $httpHandler = null
239 ) {
240 if (!$this->fetcher instanceof UpdateMetadataInterface) {
241 throw new \RuntimeException(
242 'Credentials fetcher does not implement ' .
243 'Google\Auth\UpdateMetadataInterface'
244 );
245 }
246
247 $cached = $this->fetchAuthTokenFromCache($authUri);
248 if ($cached) {
249 // Set the access token in the `Authorization` metadata header so
250 // the downstream call to updateMetadata know they don't need to
251 // fetch another token.
252 if (isset($cached['access_token'])) {
253 $metadata[self::AUTH_METADATA_KEY] = [
254 'Bearer ' . $cached['access_token']
255 ];
256 } elseif (isset($cached['id_token'])) {
257 $metadata[self::AUTH_METADATA_KEY] = [
258 'Bearer ' . $cached['id_token']
259 ];
260 }
261 }
262
263 $newMetadata = $this->fetcher->updateMetadata(
264 $metadata,
265 $authUri,
266 $httpHandler
267 );
268
269 if (!$cached && $token = $this->fetcher->getLastReceivedToken()) {
270 $this->saveAuthTokenInCache($token, $authUri);
271 }
272
273 return $newMetadata;
274 }
275
276 /**
277 * @param string|null $authUri
278 * @return array<mixed>|null
279 */
280 private function fetchAuthTokenFromCache($authUri = null)
281 {
282 // Use the cached value if its available.
283 //
284 // TODO: correct caching; update the call to setCachedValue to set the expiry
285 // to the value returned with the auth token.
286 //
287 // TODO: correct caching; enable the cache to be cleared.
288
289 // if $authUri is set, use it as the cache key
290 $cacheKey = $authUri
291 ? $this->getFullCacheKey($authUri)
292 : $this->fetcher->getCacheKey();
293
294 $cached = $this->getCachedValue($cacheKey);
295 if (is_array($cached)) {
296 if (empty($cached['expires_at'])) {
297 // If there is no expiration data, assume token is not expired.
298 // (for JwtAccess and ID tokens)
299 return $cached;
300 }
301 if ((time() + $this->eagerRefreshThresholdSeconds) < $cached['expires_at']) {
302 // access token is not expired
303 return $cached;
304 }
305 }
306
307 return null;
308 }
309
310 /**
311 * @param array<mixed> $authToken
312 * @param string|null $authUri
313 * @return void
314 */
315 private function saveAuthTokenInCache($authToken, $authUri = null)
316 {
317 if (isset($authToken['access_token']) ||
318 isset($authToken['id_token'])) {
319 // if $authUri is set, use it as the cache key
320 $cacheKey = $authUri
321 ? $this->getFullCacheKey($authUri)
322 : $this->fetcher->getCacheKey();
323
324 $this->setCachedValue($cacheKey, $authToken);
325 }
326 }
327
328 private function getCachedUniverseDomain(GetUniverseDomainInterface $fetcher): string
329 {
330 $cacheKey = $this->getFullCacheKey($fetcher->getCacheKey() . 'universe_domain'); // @phpstan-ignore-line
331 if ($universeDomain = $this->getCachedValue($cacheKey)) {
332 return $universeDomain;
333 }
334
335 $universeDomain = $fetcher->getUniverseDomain();
336 $this->setCachedValue($cacheKey, $universeDomain);
337 return $universeDomain;
338 }
339 }
340