PluginProbe
WP-Stateless – Google Cloud Storage / 2.1.4
WP-Stateless – Google Cloud Storage v2.1.4
4.4.3 2.1.7 2.1.8 2.1.9 2.2.0 2.2.1 2.2.2 2.2.3 2.2.4 2.2.5 2.2.6 2.2.7 2.3.0 2.3.1 2.3.2 3.0 3.0.1 3.0.2 3.0.3 3.0.4 3.1.0 3.1.1 3.2.0 3.2.1 3.2.2 All 62 releases
wp-stateless / lib / Google / vendor / google / auth / src / OAuth2.php

OAuth2.php in WP-Stateless – Google Cloud Storage 2.1.4, at lib/Google/vendor/google/auth/src/OAuth2.php

1,143 lines 27.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /*
3 * Copyright 2015 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 Google\Auth\FetchAuthTokenInterface;
21 use Google\Auth\HttpHandler\HttpHandlerFactory;
22 use GuzzleHttp\Psr7;
23 use GuzzleHttp\Psr7\Request;
24 use Psr\Http\Message\RequestInterface;
25 use Psr\Http\Message\ResponseInterface;
26 use Psr\Http\Message\UriInterface;
27
28 /**
29 * OAuth2 supports authentication by OAuth2 2-legged flows.
30 *
31 * It primary supports
32 * - service account authorization
33 * - authorization where a user already has an access token
34 */
35 class OAuth2 implements FetchAuthTokenInterface
36 {
37 const DEFAULT_EXPIRY_SECONDS = 3600; // 1 hour
38 const DEFAULT_SKEW_SECONDS = 60; // 1 minute
39 const JWT_URN = 'urn:ietf:params:oauth:grant-type:jwt-bearer';
40
41 /**
42 * TODO: determine known methods from the keys of JWT::methods
43 */
44 public static $knownSigningAlgorithms = array('HS256', 'HS512', 'HS384',
45 'RS256');
46
47 /**
48 * The well known grant types.
49 */
50 public static $knownGrantTypes = array('authorization_code',
51 'refresh_token',
52 'password',
53 'client_credentials');
54
55 /**
56 * - authorizationUri
57 * The authorization server's HTTP endpoint capable of
58 * authenticating the end-user and obtaining authorization.
59 */
60 private $authorizationUri;
61
62 /**
63 * - tokenCredentialUri
64 * The authorization server's HTTP endpoint capable of issuing
65 * tokens and refreshing expired tokens.
66 */
67 private $tokenCredentialUri;
68
69 /**
70 * The redirection URI used in the initial request.
71 */
72 private $redirectUri;
73
74 /**
75 * A unique identifier issued to the client to identify itself to the
76 * authorization server.
77 */
78 private $clientId;
79
80 /**
81 * A shared symmetric secret issued by the authorization server, which is
82 * used to authenticate the client.
83 */
84 private $clientSecret;
85
86 /**
87 * The resource owner's username.
88 */
89 private $username;
90
91 /**
92 * The resource owner's password.
93 */
94 private $password;
95
96 /**
97 * The scope of the access request, expressed either as an Array or as a
98 * space-delimited string.
99 */
100 private $scope;
101
102 /**
103 * An arbitrary string designed to allow the client to maintain state.
104 */
105 private $state;
106
107 /**
108 * The authorization code issued to this client.
109 *
110 * Only used by the authorization code access grant type.
111 */
112 private $code;
113
114 /**
115 * The issuer ID when using assertion profile.
116 */
117 private $issuer;
118
119 /**
120 * The target audience for assertions.
121 */
122 private $audience;
123
124 /**
125 * The target sub when issuing assertions.
126 */
127 private $sub;
128
129 /**
130 * The number of seconds assertions are valid for.
131 */
132 private $expiry;
133
134 /**
135 * The signing key when using assertion profile.
136 */
137 private $signingKey;
138
139 /**
140 * The signing algorithm when using an assertion profile.
141 */
142 private $signingAlgorithm;
143
144 /**
145 * The refresh token associated with the access token to be refreshed.
146 */
147 private $refreshToken;
148
149 /**
150 * The current access token.
151 */
152 private $accessToken;
153
154 /**
155 * The current ID token.
156 */
157 private $idToken;
158
159 /**
160 * The lifetime in seconds of the current access token.
161 */
162 private $expiresIn;
163
164 /**
165 * The expiration time of the access token as a number of seconds since the
166 * unix epoch.
167 */
168 private $expiresAt;
169
170 /**
171 * The issue time of the access token as a number of seconds since the unix
172 * epoch.
173 */
174 private $issuedAt;
175
176 /**
177 * The current grant type.
178 */
179 private $grantType;
180
181 /**
182 * When using an extension grant type, this is the set of parameters used by
183 * that extension.
184 */
185 private $extensionParams;
186
187 /**
188 * Create a new OAuthCredentials.
189 *
190 * The configuration array accepts various options
191 *
192 * - authorizationUri
193 * The authorization server's HTTP endpoint capable of
194 * authenticating the end-user and obtaining authorization.
195 *
196 * - tokenCredentialUri
197 * The authorization server's HTTP endpoint capable of issuing
198 * tokens and refreshing expired tokens.
199 *
200 * - clientId
201 * A unique identifier issued to the client to identify itself to the
202 * authorization server.
203 *
204 * - clientSecret
205 * A shared symmetric secret issued by the authorization server,
206 * which is used to authenticate the client.
207 *
208 * - scope
209 * The scope of the access request, expressed either as an Array
210 * or as a space-delimited String.
211 *
212 * - state
213 * An arbitrary string designed to allow the client to maintain state.
214 *
215 * - redirectUri
216 * The redirection URI used in the initial request.
217 *
218 * - username
219 * The resource owner's username.
220 *
221 * - password
222 * The resource owner's password.
223 *
224 * - issuer
225 * Issuer ID when using assertion profile
226 *
227 * - audience
228 * Target audience for assertions
229 *
230 * - expiry
231 * Number of seconds assertions are valid for
232 *
233 * - signingKey
234 * Signing key when using assertion profile
235 *
236 * - refreshToken
237 * The refresh token associated with the access token
238 * to be refreshed.
239 *
240 * - accessToken
241 * The current access token for this client.
242 *
243 * - idToken
244 * The current ID token for this client.
245 *
246 * - extensionParams
247 * When using an extension grant type, this is the set of parameters used
248 * by that extension.
249 *
250 * @param array $config Configuration array
251 */
252 public function __construct(array $config)
253 {
254 $opts = array_merge([
255 'expiry' => self::DEFAULT_EXPIRY_SECONDS,
256 'extensionParams' => [],
257 'authorizationUri' => null,
258 'redirectUri' => null,
259 'tokenCredentialUri' => null,
260 'state' => null,
261 'username' => null,
262 'password' => null,
263 'clientId' => null,
264 'clientSecret' => null,
265 'issuer' => null,
266 'sub' => null,
267 'audience' => null,
268 'signingKey' => null,
269 'signingAlgorithm' => null,
270 'scope' => null
271 ], $config);
272
273 $this->setAuthorizationUri($opts['authorizationUri']);
274 $this->setRedirectUri($opts['redirectUri']);
275 $this->setTokenCredentialUri($opts['tokenCredentialUri']);
276 $this->setState($opts['state']);
277 $this->setUsername($opts['username']);
278 $this->setPassword($opts['password']);
279 $this->setClientId($opts['clientId']);
280 $this->setClientSecret($opts['clientSecret']);
281 $this->setIssuer($opts['issuer']);
282 $this->setSub($opts['sub']);
283 $this->setExpiry($opts['expiry']);
284 $this->setAudience($opts['audience']);
285 $this->setSigningKey($opts['signingKey']);
286 $this->setSigningAlgorithm($opts['signingAlgorithm']);
287 $this->setScope($opts['scope']);
288 $this->setExtensionParams($opts['extensionParams']);
289 $this->updateToken($opts);
290 }
291
292 /**
293 * Verifies the idToken if present.
294 *
295 * - if none is present, return null
296 * - if present, but invalid, raises DomainException.
297 * - otherwise returns the payload in the idtoken as a PHP object.
298 *
299 * if $publicKey is null, the key is decoded without being verified.
300 *
301 * @param $publicKey the publicKey to use to authenticate the token
302 * @param Array $allowed_algs List of supported verification algorithms
303 */
304 public function verifyIdToken($publicKey = null, $allowed_algs = array())
305 {
306 $idToken = $this->getIdToken();
307 if (is_null($idToken)) {
308 return null;
309 }
310
311 $resp = $this->jwtDecode($idToken, $publicKey, $allowed_algs);
312 if (!property_exists($resp, 'aud')) {
313 throw new \DomainException('No audience found the id token');
314 }
315 if ($resp->aud != $this->getAudience()) {
316 throw new \DomainException('Wrong audience present in the id token');
317 }
318 return $resp;
319 }
320
321 /**
322 * Obtains the encoded jwt from the instance data.
323 *
324 * @param $config array optional configuration parameters
325 */
326 public function toJwt(array $config = [])
327 {
328 if (is_null($this->getSigningKey())) {
329 throw new \DomainException('No signing key available');
330 }
331 if (is_null($this->getSigningAlgorithm())) {
332 throw new \DomainException('No signing algorithm specified');
333 }
334 $now = time();
335
336 $opts = array_merge([
337 'skew' => self::DEFAULT_SKEW_SECONDS
338 ], $config);
339
340 $assertion = [
341 'iss' => $this->getIssuer(),
342 'aud' => $this->getAudience(),
343 'exp' => ($now + $this->getExpiry()),
344 'iat' => ($now - $opts['skew'])
345 ];
346 foreach ($assertion as $k => $v) {
347 if (is_null($v)) {
348 throw new \DomainException($k . ' should not be null');
349 }
350 }
351 if (!(is_null($this->getScope()))) {
352 $assertion['scope'] = $this->getScope();
353 }
354 if (!(is_null($this->getSub()))) {
355 $assertion['sub'] = $this->getSub();
356 }
357 return $this->jwtEncode($assertion, $this->getSigningKey(),
358 $this->getSigningAlgorithm());
359 }
360
361 /**
362 * Generates a request for token credentials.
363 *
364 * @return RequestInterface the authorization Url.
365 */
366 public function generateCredentialsRequest()
367 {
368 $uri = $this->getTokenCredentialUri();
369 if (is_null($uri)) {
370 throw new \DomainException('No token credential URI was set.');
371 }
372
373 $grantType = $this->getGrantType();
374 $params = array('grant_type' => $grantType);
375 switch($grantType) {
376 case 'authorization_code':
377 $params['code'] = $this->getCode();
378 $params['redirect_uri'] = $this->getRedirectUri();
379 $this->addClientCredentials($params);
380 break;
381 case 'password':
382 $params['username'] = $this->getUsername();
383 $params['password'] = $this->getPassword();
384 $this->addClientCredentials($params);
385 break;
386 case 'refresh_token':
387 $params['refresh_token'] = $this->getRefreshToken();
388 $this->addClientCredentials($params);
389 break;
390 case self::JWT_URN:
391 $params['assertion'] = $this->toJwt();
392 break;
393 default:
394 if (!is_null($this->getRedirectUri())) {
395 # Grant type was supposed to be 'authorization_code', as there
396 # is a redirect URI.
397 throw new \DomainException('Missing authorization code');
398 }
399 unset($params['grant_type']);
400 if (!is_null($grantType)) {
401 $params['grant_type'] = $grantType;
402 }
403 $params = array_merge($params, $this->getExtensionParams());
404 }
405
406 $headers = [
407 'Cache-Control' => 'no-store',
408 'Content-Type' => 'application/x-www-form-urlencoded'
409 ];
410
411 return new Request(
412 'POST',
413 $uri,
414 $headers,
415 Psr7\build_query($params)
416 );
417 }
418
419 /**
420 * Fetchs the auth tokens based on the current state.
421 *
422 * @param callable $httpHandler callback which delivers psr7 request
423 * @return array the response
424 */
425 public function fetchAuthToken(callable $httpHandler = null)
426 {
427 if (is_null($httpHandler)) {
428 $httpHandler = HttpHandlerFactory::build();
429 }
430
431 $response = $httpHandler($this->generateCredentialsRequest());
432 $creds = $this->parseTokenResponse($response);
433 $this->updateToken($creds);
434 return $creds;
435 }
436
437 /**
438 * Obtains a key that can used to cache the results of #fetchAuthToken.
439 *
440 * The key is derived from the scopes.
441 *
442 * @return string a key that may be used to cache the auth token.
443 */
444 public function getCacheKey() {
445 if (is_string($this->scope)) {
446 return $this->scope;
447 } else if (is_array($this->scope)) {
448 return implode(":", $this->scope);
449 }
450
451 // If scope has not set, return null to indicate no caching.
452 return null;
453 }
454
455 /**
456 * Parses the fetched tokens.
457 *
458 * @param $resp ReponseInterface the response.
459 * @return array the tokens parsed from the response body.
460 */
461 public function parseTokenResponse(ResponseInterface $resp)
462 {
463 $body = (string) $resp->getBody();
464 if ($resp->hasHeader('Content-Type') &&
465 $resp->getHeaderLine('Content-Type') == 'application/x-www-form-urlencoded') {
466 $res = array();
467 parse_str($body, $res);
468 return $res;
469 } else {
470 // Assume it's JSON; if it's not throw an exception
471 if (null === $res = json_decode($body, true)) {
472 throw new \Exception('Invalid JSON response');
473 }
474
475 return $res;
476 }
477 }
478
479 /**
480 * Updates an OAuth 2.0 client.
481 *
482 * @example
483 * client.updateToken([
484 * 'refresh_token' => 'n4E9O119d',
485 * 'access_token' => 'FJQbwq9',
486 * 'expires_in' => 3600
487 * ])
488 *
489 * @param array options
490 * The configuration parameters related to the token.
491 *
492 * - refresh_token
493 * The refresh token associated with the access token
494 * to be refreshed.
495 *
496 * - access_token
497 * The current access token for this client.
498 *
499 * - id_token
500 * The current ID token for this client.
501 *
502 * - expires_in
503 * The time in seconds until access token expiration.
504 *
505 * - expires_at
506 * The time as an integer number of seconds since the Epoch
507 *
508 * - issued_at
509 * The timestamp that the token was issued at.
510 */
511 public function updateToken(array $config)
512 {
513 $opts = array_merge([
514 'extensionParams' => [],
515 'refresh_token' => null,
516 'access_token' => null,
517 'id_token' => null,
518 'expires' => null,
519 'expires_in' => null,
520 'expires_at' => null,
521 'issued_at' => null
522 ], $config);
523
524 $this->setExpiresAt($opts['expires']);
525 $this->setExpiresAt($opts['expires_at']);
526 $this->setExpiresIn($opts['expires_in']);
527 // By default, the token is issued at `Time.now` when `expiresIn` is set,
528 // but this can be used to supply a more precise time.
529 if (!is_null($opts['issued_at'])) {
530 $this->setIssuedAt($opts['issued_at']);
531 }
532
533 $this->setAccessToken($opts['access_token']);
534 $this->setIdToken($opts['id_token']);
535 $this->setRefreshToken($opts['refresh_token']);
536 }
537
538 /**
539 * Builds the authorization Uri that the user should be redirected to.
540 *
541 * @param $config configuration options that customize the return url
542 * @return UriInterface the authorization Url.
543 * @throws InvalidArgumentException
544 */
545 public function buildFullAuthorizationUri(array $config = [])
546 {
547 if (is_null($this->getAuthorizationUri())) {
548 throw new \InvalidArgumentException(
549 'requires an authorizationUri to have been set');
550 }
551
552 $params = array_merge([
553 'response_type' => 'code',
554 'access_type' => 'offline',
555 'client_id' => $this->clientId,
556 'redirect_uri' => $this->redirectUri,
557 'state' => $this->state,
558 'scope' => $this->getScope(),
559 ], $config);
560
561 // Validate the auth_params
562 if (is_null($params['client_id'])) {
563 throw new \InvalidArgumentException(
564 'missing the required client identifier');
565 }
566 if (is_null($params['redirect_uri'])) {
567 throw new \InvalidArgumentException('missing the required redirect URI');
568 }
569 if (!empty($params['prompt']) && !empty($params['approval_prompt'])) {
570 throw new \InvalidArgumentException(
571 'prompt and approval_prompt are mutually exclusive');
572 }
573
574 // Construct the uri object; return it if it is valid.
575 $result = clone $this->authorizationUri;
576 $existingParams = Psr7\parse_query($result->getQuery());
577
578 $result = $result->withQuery(
579 Psr7\build_query(array_merge($existingParams, $params))
580 );
581
582 if ($result->getScheme() != 'https') {
583 throw new \InvalidArgumentException(
584 'Authorization endpoint must be protected by TLS');
585 }
586 return $result;
587 }
588
589 /**
590 * Sets the authorization server's HTTP endpoint capable of authenticating
591 * the end-user and obtaining authorization.
592 */
593 public function setAuthorizationUri($uri)
594 {
595 $this->authorizationUri = $this->coerceUri($uri);
596 }
597
598 /**
599 * Gets the authorization server's HTTP endpoint capable of authenticating
600 * the end-user and obtaining authorization.
601 */
602 public function getAuthorizationUri()
603 {
604 return $this->authorizationUri;
605 }
606
607 /**
608 * Gets the authorization server's HTTP endpoint capable of issuing tokens
609 * and refreshing expired tokens.
610 */
611 public function getTokenCredentialUri()
612 {
613 return $this->tokenCredentialUri;
614 }
615
616 /**
617 * Sets the authorization server's HTTP endpoint capable of issuing tokens
618 * and refreshing expired tokens.
619 */
620 public function setTokenCredentialUri($uri)
621 {
622 $this->tokenCredentialUri = $this->coerceUri($uri);
623 }
624
625 /**
626 * Gets the redirection URI used in the initial request.
627 */
628 public function getRedirectUri()
629 {
630 return $this->redirectUri;
631 }
632
633 /**
634 * Sets the redirection URI used in the initial request.
635 */
636 public function setRedirectUri($uri)
637 {
638 if (is_null($uri)) {
639 $this->redirectUri = null;
640 return;
641 }
642 // redirect URI must be absolute
643 if (!$this->isAbsoluteUri($uri)) {
644 // "postmessage" is a reserved URI string in Google-land
645 // @see https://developers.google.com/identity/sign-in/web/server-side-flow
646 if ('postmessage' !== (string) $uri) {
647 throw new \InvalidArgumentException(
648 'Redirect URI must be absolute');
649 }
650 }
651 $this->redirectUri = (string) $uri;
652 }
653
654 /**
655 * Gets the scope of the access requests as a space-delimited String.
656 */
657 public function getScope()
658 {
659 if (is_null($this->scope)) {
660 return $this->scope;
661 }
662 return implode(' ', $this->scope);
663 }
664
665 /**
666 * Sets the scope of the access request, expressed either as an Array or as
667 * a space-delimited String.
668 */
669 public function setScope($scope)
670 {
671 if (is_null($scope)) {
672 $this->scope = null;
673 } else if (is_string($scope)) {
674 $this->scope = explode(' ', $scope);
675 } else if (is_array($scope)) {
676 foreach ($scope as $s) {
677 $pos = strpos($s, ' ');
678 if ($pos !== false) {
679 throw new \InvalidArgumentException(
680 'array scope values should not contain spaces');
681 }
682 }
683 $this->scope = $scope;
684 } else {
685 throw new \InvalidArgumentException(
686 'scopes should be a string or array of strings');
687 }
688 }
689
690 /**
691 * Gets the current grant type.
692 */
693 public function getGrantType()
694 {
695 if (!is_null($this->grantType)) {
696 return $this->grantType;
697 }
698
699 // Returns the inferred grant type, based on the current object instance
700 // state.
701 if (!is_null($this->code)) {
702 return 'authorization_code';
703 } else if (!is_null($this->refreshToken)) {
704 return 'refresh_token';
705 } else if (!is_null($this->username) && !is_null($this->password)) {
706 return 'password';
707 } else if (!is_null($this->issuer) && !is_null($this->signingKey)) {
708 return self::JWT_URN;
709 } else {
710 return null;
711 }
712 }
713
714 /**
715 * Sets the current grant type.
716 */
717 public function setGrantType($gt)
718 {
719 if (in_array($gt, self::$knownGrantTypes)) {
720 $this->grantType = $gt;
721 } else {
722 // validate URI
723 if (!$this->isAbsoluteUri($gt)) {
724 throw new \InvalidArgumentException(
725 'invalid grant type');
726 }
727 $this->grantType = (string) $gt;
728 }
729 }
730
731 /**
732 * Gets an arbitrary string designed to allow the client to maintain state.
733 */
734 public function getState()
735 {
736 return $this->state;
737 }
738
739 /**
740 * Sets an arbitrary string designed to allow the client to maintain state.
741 */
742 public function setState($state)
743 {
744 $this->state = $state;
745 }
746
747 /**
748 * Gets the authorization code issued to this client.
749 */
750 public function getCode()
751 {
752 return $this->code;
753 }
754
755 /**
756 * Sets the authorization code issued to this client.
757 */
758 public function setCode($code)
759 {
760 $this->code = $code;
761 }
762
763 /**
764 * Gets the resource owner's username.
765 */
766 public function getUsername()
767 {
768 return $this->username;
769 }
770
771 /**
772 * Sets the resource owner's username.
773 */
774 public function setUsername($username)
775 {
776 $this->username = $username;
777 }
778
779 /**
780 * Gets the resource owner's password.
781 */
782 public function getPassword()
783 {
784 return $this->password;
785 }
786
787 /**
788 * Sets the resource owner's password.
789 */
790 public function setPassword($password)
791 {
792 $this->password = $password;
793 }
794
795 /**
796 * Sets a unique identifier issued to the client to identify itself to the
797 * authorization server.
798 */
799 public function getClientId()
800 {
801 return $this->clientId;
802 }
803
804 /**
805 * Sets a unique identifier issued to the client to identify itself to the
806 * authorization server.
807 */
808 public function setClientId($clientId)
809 {
810 $this->clientId = $clientId;
811 }
812
813 /**
814 * Gets a shared symmetric secret issued by the authorization server, which
815 * is used to authenticate the client.
816 */
817 public function getClientSecret()
818 {
819 return $this->clientSecret;
820 }
821
822 /**
823 * Sets a shared symmetric secret issued by the authorization server, which
824 * is used to authenticate the client.
825 */
826 public function setClientSecret($clientSecret)
827 {
828 $this->clientSecret = $clientSecret;
829 }
830
831 /**
832 * Gets the Issuer ID when using assertion profile.
833 */
834 public function getIssuer()
835 {
836 return $this->issuer;
837 }
838
839 /**
840 * Sets the Issuer ID when using assertion profile.
841 */
842 public function setIssuer($issuer)
843 {
844 $this->issuer = $issuer;
845 }
846
847 /**
848 * Gets the target sub when issuing assertions.
849 */
850 public function getSub()
851 {
852 return $this->sub;
853 }
854
855 /**
856 * Sets the target sub when issuing assertions.
857 */
858 public function setSub($sub)
859 {
860 $this->sub = $sub;
861 }
862
863 /**
864 * Gets the target audience when issuing assertions.
865 */
866 public function getAudience()
867 {
868 return $this->audience;
869 }
870
871 /**
872 * Sets the target audience when issuing assertions.
873 */
874 public function setAudience($audience)
875 {
876 $this->audience = $audience;
877 }
878
879 /**
880 * Gets the signing key when using an assertion profile.
881 */
882 public function getSigningKey()
883 {
884 return $this->signingKey;
885 }
886
887 /**
888 * Sets the signing key when using an assertion profile.
889 */
890 public function setSigningKey($signingKey)
891 {
892 $this->signingKey = $signingKey;
893 }
894
895 /**
896 * Gets the signing algorithm when using an assertion profile.
897 */
898 public function getSigningAlgorithm()
899 {
900 return $this->signingAlgorithm;
901 }
902
903 /**
904 * Sets the signing algorithm when using an assertion profile.
905 */
906 public function setSigningAlgorithm($sa)
907 {
908 if (is_null($sa)) {
909 $this->signingAlgorithm = null;
910 } else if (!in_array($sa, self::$knownSigningAlgorithms)) {
911 throw new \InvalidArgumentException('unknown signing algorithm');
912 } else {
913 $this->signingAlgorithm = $sa;
914 }
915 }
916
917 /**
918 * Gets the set of parameters used by extension when using an extension
919 * grant type.
920 */
921 public function getExtensionParams()
922 {
923 return $this->extensionParams;
924 }
925
926 /**
927 * Sets the set of parameters used by extension when using an extension
928 * grant type.
929 */
930 public function setExtensionParams($extensionParams)
931 {
932 $this->extensionParams = $extensionParams;
933 }
934
935 /**
936 * Gets the number of seconds assertions are valid for.
937 */
938 public function getExpiry()
939 {
940 return $this->expiry;
941 }
942
943 /**
944 * Sets the number of seconds assertions are valid for.
945 */
946 public function setExpiry($expiry)
947 {
948 $this->expiry = $expiry;
949 }
950
951 /**
952 * Gets the lifetime of the access token in seconds.
953 */
954 public function getExpiresIn()
955 {
956 return $this->expiresIn;
957 }
958
959 /**
960 * Sets the lifetime of the access token in seconds.
961 */
962 public function setExpiresIn($expiresIn)
963 {
964 if (is_null($expiresIn)) {
965 $this->expiresIn = null;
966 $this->issuedAt = null;
967 } else {
968 $this->issuedAt = time();
969 $this->expiresIn = (int) $expiresIn;
970 }
971 }
972
973 /**
974 * Gets the time the current access token expires at.
975 */
976 public function getExpiresAt()
977 {
978 if (!is_null($this->expiresAt)) {
979 return $this->expiresAt;
980 } else if (!is_null($this->issuedAt) && !is_null($this->expiresIn)) {
981 return $this->issuedAt + $this->expiresIn;
982 }
983 return null;
984 }
985
986 /**
987 * Returns true if the acccess token has expired.
988 */
989 public function isExpired()
990 {
991 $expiration = $this->getExpiresAt();
992 $now = time();
993 return (!is_null($expiration) && $now >= $expiration);
994 }
995
996 /**
997 * Sets the time the current access token expires at.
998 */
999 public function setExpiresAt($expiresAt)
1000 {
1001 $this->expiresAt = $expiresAt;
1002 }
1003
1004 /**
1005 * Gets the time the current access token was issued at.
1006 */
1007 public function getIssuedAt()
1008 {
1009 return $this->issuedAt;
1010 }
1011
1012 /**
1013 * Sets the time the current access token was issued at.
1014 */
1015 public function setIssuedAt($issuedAt)
1016 {
1017 $this->issuedAt = $issuedAt;
1018 }
1019
1020 /**
1021 * Gets the current access token.
1022 */
1023 public function getAccessToken()
1024 {
1025 return $this->accessToken;
1026 }
1027
1028 /**
1029 * Sets the current access token.
1030 */
1031 public function setAccessToken($accessToken)
1032 {
1033 $this->accessToken = $accessToken;
1034 }
1035
1036 /**
1037 * Gets the current ID token.
1038 */
1039 public function getIdToken()
1040 {
1041 return $this->idToken;
1042 }
1043
1044 /**
1045 * Sets the current ID token.
1046 */
1047 public function setIdToken($idToken)
1048 {
1049 $this->idToken = $idToken;
1050 }
1051
1052 /**
1053 * Gets the refresh token associated with the current access token.
1054 */
1055 public function getRefreshToken()
1056 {
1057 return $this->refreshToken;
1058 }
1059
1060 /**
1061 * Sets the refresh token associated with the current access token.
1062 */
1063 public function setRefreshToken($refreshToken)
1064 {
1065 $this->refreshToken = $refreshToken;
1066 }
1067
1068 /**
1069 * The expiration of the last received token
1070 */
1071 public function getLastReceivedToken()
1072 {
1073 if ($token = $this->getAccessToken()) {
1074 return [
1075 'access_token' => $token,
1076 'expires_at' => $this->getExpiresAt(),
1077 ];
1078 }
1079
1080 return null;
1081 }
1082
1083 /**
1084 * @todo handle uri as array
1085 * @param string $uri
1086 * @return null|UriInterface
1087 */
1088 private function coerceUri($uri)
1089 {
1090 if (is_null($uri)) {
1091 return null;
1092 }
1093
1094 return Psr7\uri_for($uri);
1095 }
1096
1097 private function jwtDecode($idToken, $publicKey, $allowedAlgs)
1098 {
1099 if (class_exists('Firebase\JWT\JWT')) {
1100 return \Firebase\JWT\JWT::decode($idToken, $publicKey, $allowedAlgs);
1101 }
1102
1103 return \JWT::decode($idToken, $publicKey, $allowedAlgs);
1104 }
1105
1106 private function jwtEncode($assertion, $signingKey, $signingAlgorithm)
1107 {
1108 if (class_exists('Firebase\JWT\JWT')) {
1109 return \Firebase\JWT\JWT::encode($assertion, $signingKey,
1110 $signingAlgorithm);
1111 }
1112
1113 return \JWT::encode($assertion, $signingKey, $signingAlgorithm);
1114 }
1115
1116 /**
1117 * Determines if the URI is absolute based on its scheme and host or path
1118 * (RFC 3986)
1119 *
1120 * @param string $uri
1121 * @return bool
1122 */
1123 private function isAbsoluteUri($uri)
1124 {
1125 $u = $this->coerceUri($uri);
1126
1127 return $u->getScheme() && ($u->getHost() || $u->getPath());
1128 }
1129
1130 private function addClientCredentials(&$params)
1131 {
1132 $clientId = $this->getClientId();
1133 $clientSecret = $this->getClientSecret();
1134
1135 if ($clientId && $clientSecret) {
1136 $params['client_id'] = $clientId;
1137 $params['client_secret'] = $clientSecret;
1138 }
1139
1140 return $params;
1141 }
1142 }
1143