← All changes
|
includes/sdk/google/google/auth/src/Credentials/UserRefreshCredentials.php
+63
-24
1.2.0
→
1.4.1
View file →
| @@ -14,13 +14,15 @@ | ||
| 14 | 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 15 | 15 | * See the License for the specific language governing permissions and |
| 16 | 16 | * limitations under the License. |
| 17 | 17 | */ |
| 18 | -namespace Dudlewebs\WPMCS\Google\Auth\Credentials; | |
| 18 | +namespace Dudlewebs\WPMCS\GCP\Google\Auth\Credentials; | |
| 19 | 19 | |
| 20 | -use Dudlewebs\WPMCS\Google\Auth\CredentialsLoader; | |
| 21 | -use Dudlewebs\WPMCS\Google\Auth\GetQuotaProjectInterface; | |
| 22 | -use Dudlewebs\WPMCS\Google\Auth\OAuth2; | |
| 20 | +use Dudlewebs\WPMCS\GCP\Google\Auth\CredentialsLoader; | |
| 21 | +use Dudlewebs\WPMCS\GCP\Google\Auth\GetQuotaProjectInterface; | |
| 22 | +use Dudlewebs\WPMCS\GCP\Google\Auth\OAuth2; | |
| 23 | +use InvalidArgumentException; | |
| 24 | +use LogicException; | |
| 23 | 25 | /** |
| 24 | 26 | * Authenticates requests using User Refresh credentials. |
| 25 | 27 | * |
| 26 | 28 | * This class allows authorizing requests from user refresh tokens. |
| @@ -33,8 +35,14 @@ | ||
| 33 | 35 | */ |
| 34 | 36 | class UserRefreshCredentials extends CredentialsLoader implements GetQuotaProjectInterface |
| 35 | 37 | { |
| 36 | 38 | /** |
| 39 | + * Used in observability metric headers | |
| 40 | + * | |
| 41 | + * @var string | |
| 42 | + */ | |
| 43 | + private const CRED_TYPE = 'u'; | |
| 44 | + /** | |
| 37 | 45 | * The OAuth2 instance used to conduct authorization. |
| 38 | 46 | * |
| 39 | 47 | * @var OAuth2 |
| 40 | 48 | */ |
| @@ -45,42 +53,60 @@ | ||
| 45 | 53 | * @var string |
| 46 | 54 | */ |
| 47 | 55 | protected $quotaProject; |
| 48 | 56 | /** |
| 57 | + * Whether this is an ID token request or an access token request. Used when | |
| 58 | + * building the metric header. | |
| 59 | + */ | |
| 60 | + private bool $isIdTokenRequest = \false; | |
| 61 | + /** | |
| 49 | 62 | * Create a new UserRefreshCredentials. |
| 50 | 63 | * |
| 51 | - * @param string|string[] $scope the scope of the access request, expressed | |
| 64 | + * @param string|string[]|null $scope the scope of the access request, expressed | |
| 52 | 65 | * either as an Array or as a space-delimited String. |
| 53 | 66 | * @param string|array<mixed> $jsonKey JSON credential file path or JSON credentials |
| 54 | 67 | * as an associative array |
| 68 | + * @param string|null $targetAudience The audience for the ID token. | |
| 55 | 69 | */ |
| 56 | - public function __construct($scope, $jsonKey) | |
| 70 | + public function __construct($scope, $jsonKey, ?string $targetAudience = null) | |
| 57 | 71 | { |
| 58 | - if (is_string($jsonKey)) { | |
| 59 | - if (!file_exists($jsonKey)) { | |
| 60 | - throw new \InvalidArgumentException('file does not exist'); | |
| 72 | + if (\is_string($jsonKey)) { | |
| 73 | + if (!\file_exists($jsonKey)) { | |
| 74 | + throw new InvalidArgumentException('file does not exist or is unreadable'); | |
| 61 | 75 | } |
| 62 | - $json = file_get_contents($jsonKey); | |
| 63 | - if (!$jsonKey = json_decode((string) $json, \true)) { | |
| 64 | - throw new \LogicException('invalid json for auth config'); | |
| 76 | + $json = \file_get_contents($jsonKey); | |
| 77 | + if (!($jsonKey = \json_decode((string) $json, \true))) { | |
| 78 | + throw new LogicException('invalid json for auth config'); | |
| 65 | 79 | } |
| 66 | 80 | } |
| 67 | - if (!array_key_exists('client_id', $jsonKey)) { | |
| 68 | - throw new \InvalidArgumentException('json key is missing the client_id field'); | |
| 81 | + if (!\array_key_exists('client_id', $jsonKey)) { | |
| 82 | + throw new InvalidArgumentException('json key is missing the client_id field'); | |
| 69 | 83 | } |
| 70 | - if (!array_key_exists('client_secret', $jsonKey)) { | |
| 71 | - throw new \InvalidArgumentException('json key is missing the client_secret field'); | |
| 84 | + if (!\array_key_exists('client_secret', $jsonKey)) { | |
| 85 | + throw new InvalidArgumentException('json key is missing the client_secret field'); | |
| 72 | 86 | } |
| 73 | - if (!array_key_exists('refresh_token', $jsonKey)) { | |
| 74 | - throw new \InvalidArgumentException('json key is missing the refresh_token field'); | |
| 87 | + if (!\array_key_exists('refresh_token', $jsonKey)) { | |
| 88 | + throw new InvalidArgumentException('json key is missing the refresh_token field'); | |
| 75 | 89 | } |
| 76 | - $this->auth = new OAuth2(['clientId' => $jsonKey['client_id'], 'clientSecret' => $jsonKey['client_secret'], 'refresh_token' => $jsonKey['refresh_token'], 'scope' => $scope, 'tokenCredentialUri' => self::TOKEN_CREDENTIAL_URI]); | |
| 77 | - if (array_key_exists('quota_project_id', $jsonKey)) { | |
| 90 | + if ($scope && $targetAudience) { | |
| 91 | + throw new InvalidArgumentException('Scope and targetAudience cannot both be supplied'); | |
| 92 | + } | |
| 93 | + $additionalClaims = []; | |
| 94 | + if ($targetAudience) { | |
| 95 | + $additionalClaims = ['target_audience' => $targetAudience]; | |
| 96 | + $this->isIdTokenRequest = \true; | |
| 97 | + } | |
| 98 | + $this->auth = new OAuth2(['clientId' => $jsonKey['client_id'], 'clientSecret' => $jsonKey['client_secret'], 'refresh_token' => $jsonKey['refresh_token'], 'scope' => $scope, 'tokenCredentialUri' => self::TOKEN_CREDENTIAL_URI, 'additionalClaims' => $additionalClaims]); | |
| 99 | + if (\array_key_exists('quota_project_id', $jsonKey)) { | |
| 78 | 100 | $this->quotaProject = (string) $jsonKey['quota_project_id']; |
| 79 | 101 | } |
| 80 | 102 | } |
| 81 | 103 | /** |
| 82 | - * @param callable $httpHandler | |
| 104 | + * @param callable|null $httpHandler | |
| 105 | + * @param array<mixed> $headers [optional] Metrics headers to be inserted | |
| 106 | + * into the token endpoint request present. | |
| 107 | + * This could be passed from ImersonatedServiceAccountCredentials as it uses | |
| 108 | + * UserRefreshCredentials as source credentials. | |
| 83 | 109 | * |
| 84 | 110 | * @return array<mixed> { |
| 85 | 111 | * A set of auth related metadata, containing the following |
| 86 | 112 | * |
| @@ -90,18 +116,27 @@ | ||
| 90 | 116 | * @type string $token_type |
| 91 | 117 | * @type string $id_token |
| 92 | 118 | * } |
| 93 | 119 | */ |
| 94 | - public function fetchAuthToken(callable $httpHandler = null) | |
| 120 | + public function fetchAuthToken(?callable $httpHandler = null, array $headers = []) | |
| 95 | 121 | { |
| 96 | - return $this->auth->fetchAuthToken($httpHandler); | |
| 122 | + return $this->auth->fetchAuthToken($httpHandler, $this->applyTokenEndpointMetrics($headers, $this->isIdTokenRequest ? 'it' : 'at')); | |
| 97 | 123 | } |
| 98 | 124 | /** |
| 125 | + * Return the Cache Key for the credentials. | |
| 126 | + * The format for the Cache key is one of the following: | |
| 127 | + * ClientId.Scope | |
| 128 | + * ClientId.Audience | |
| 129 | + * | |
| 99 | 130 | * @return string |
| 100 | 131 | */ |
| 101 | 132 | public function getCacheKey() |
| 102 | 133 | { |
| 103 | - return $this->auth->getClientId() . ':' . $this->auth->getCacheKey(); | |
| 134 | + $scopeOrAudience = $this->auth->getScope(); | |
| 135 | + if (!$scopeOrAudience) { | |
| 136 | + $scopeOrAudience = $this->auth->getAudience(); | |
| 137 | + } | |
| 138 | + return $this->auth->getClientId() . '.' . $scopeOrAudience; | |
| 104 | 139 | } |
| 105 | 140 | /** |
| 106 | 141 | * @return array<mixed> |
| 107 | 142 | */ |
| @@ -125,6 +160,10 @@ | ||
| 125 | 160 | */ |
| 126 | 161 | public function getGrantedScope() |
| 127 | 162 | { |
| 128 | 163 | return $this->auth->getGrantedScope(); |
| 164 | + } | |
| 165 | + protected function getCredType() : string | |
| 166 | + { | |
| 167 | + return self::CRED_TYPE; | |
| 129 | 168 | } |
| 130 | 169 | } |