Initial commit
This commit is contained in:
269
vendor/google/apiclient/src/Google/AccessToken/Verify.php
vendored
Normal file
269
vendor/google/apiclient/src/Google/AccessToken/Verify.php
vendored
Normal file
@@ -0,0 +1,269 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2008 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
use Firebase\JWT\ExpiredException as ExpiredExceptionV3;
|
||||
use GuzzleHttp\Client;
|
||||
use GuzzleHttp\ClientInterface;
|
||||
use Psr\Cache\CacheItemPoolInterface;
|
||||
use Google\Auth\Cache\MemoryCacheItemPool;
|
||||
use Stash\Driver\FileSystem;
|
||||
use Stash\Pool;
|
||||
|
||||
/**
|
||||
* Wrapper around Google Access Tokens which provides convenience functions
|
||||
*
|
||||
*/
|
||||
class Google_AccessToken_Verify
|
||||
{
|
||||
const FEDERATED_SIGNON_CERT_URL = 'https://www.googleapis.com/oauth2/v3/certs';
|
||||
const OAUTH2_ISSUER = 'accounts.google.com';
|
||||
const OAUTH2_ISSUER_HTTPS = 'https://accounts.google.com';
|
||||
|
||||
/**
|
||||
* @var GuzzleHttp\ClientInterface The http client
|
||||
*/
|
||||
private $http;
|
||||
|
||||
/**
|
||||
* @var Psr\Cache\CacheItemPoolInterface cache class
|
||||
*/
|
||||
private $cache;
|
||||
|
||||
/**
|
||||
* Instantiates the class, but does not initiate the login flow, leaving it
|
||||
* to the discretion of the caller.
|
||||
*/
|
||||
public function __construct(
|
||||
ClientInterface $http = null,
|
||||
CacheItemPoolInterface $cache = null,
|
||||
$jwt = null
|
||||
) {
|
||||
if (null === $http) {
|
||||
$http = new Client();
|
||||
}
|
||||
|
||||
if (null === $cache) {
|
||||
$cache = new MemoryCacheItemPool;
|
||||
}
|
||||
|
||||
$this->http = $http;
|
||||
$this->cache = $cache;
|
||||
$this->jwt = $jwt ?: $this->getJwtService();
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies an id token and returns the authenticated apiLoginTicket.
|
||||
* Throws an exception if the id token is not valid.
|
||||
* The audience parameter can be used to control which id tokens are
|
||||
* accepted. By default, the id token must have been issued to this OAuth2 client.
|
||||
*
|
||||
* @param $audience
|
||||
* @return array the token payload, if successful
|
||||
*/
|
||||
public function verifyIdToken($idToken, $audience = null)
|
||||
{
|
||||
if (empty($idToken)) {
|
||||
throw new LogicException('id_token cannot be null');
|
||||
}
|
||||
|
||||
// set phpseclib constants if applicable
|
||||
$this->setPhpsecConstants();
|
||||
|
||||
// Check signature
|
||||
$certs = $this->getFederatedSignOnCerts();
|
||||
foreach ($certs as $cert) {
|
||||
$bigIntClass = $this->getBigIntClass();
|
||||
$rsaClass = $this->getRsaClass();
|
||||
$modulus = new $bigIntClass($this->jwt->urlsafeB64Decode($cert['n']), 256);
|
||||
$exponent = new $bigIntClass($this->jwt->urlsafeB64Decode($cert['e']), 256);
|
||||
|
||||
$rsa = new $rsaClass();
|
||||
$rsa->loadKey(array('n' => $modulus, 'e' => $exponent));
|
||||
|
||||
try {
|
||||
$payload = $this->jwt->decode(
|
||||
$idToken,
|
||||
$rsa->getPublicKey(),
|
||||
array('RS256')
|
||||
);
|
||||
|
||||
if (property_exists($payload, 'aud')) {
|
||||
if ($audience && $payload->aud != $audience) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// support HTTP and HTTPS issuers
|
||||
// @see https://developers.google.com/identity/sign-in/web/backend-auth
|
||||
$issuers = array(self::OAUTH2_ISSUER, self::OAUTH2_ISSUER_HTTPS);
|
||||
if (!isset($payload->iss) || !in_array($payload->iss, $issuers)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (array) $payload;
|
||||
} catch (ExpiredException $e) {
|
||||
return false;
|
||||
} catch (ExpiredExceptionV3 $e) {
|
||||
return false;
|
||||
} catch (DomainException $e) {
|
||||
// continue
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private function getCache()
|
||||
{
|
||||
return $this->cache;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve and cache a certificates file.
|
||||
*
|
||||
* @param $url string location
|
||||
* @throws Google_Exception
|
||||
* @return array certificates
|
||||
*/
|
||||
private function retrieveCertsFromLocation($url)
|
||||
{
|
||||
// If we're retrieving a local file, just grab it.
|
||||
if (0 !== strpos($url, 'http')) {
|
||||
if (!$file = file_get_contents($url)) {
|
||||
throw new Google_Exception(
|
||||
"Failed to retrieve verification certificates: '" .
|
||||
$url . "'."
|
||||
);
|
||||
}
|
||||
|
||||
return json_decode($file, true);
|
||||
}
|
||||
|
||||
$response = $this->http->get($url);
|
||||
|
||||
if ($response->getStatusCode() == 200) {
|
||||
return json_decode((string) $response->getBody(), true);
|
||||
}
|
||||
throw new Google_Exception(
|
||||
sprintf(
|
||||
'Failed to retrieve verification certificates: "%s".',
|
||||
$response->getBody()->getContents()
|
||||
),
|
||||
$response->getStatusCode()
|
||||
);
|
||||
}
|
||||
|
||||
// Gets federated sign-on certificates to use for verifying identity tokens.
|
||||
// Returns certs as array structure, where keys are key ids, and values
|
||||
// are PEM encoded certificates.
|
||||
private function getFederatedSignOnCerts()
|
||||
{
|
||||
$certs = null;
|
||||
if ($cache = $this->getCache()) {
|
||||
$cacheItem = $cache->getItem('federated_signon_certs_v3', 3600);
|
||||
$certs = $cacheItem->get();
|
||||
}
|
||||
|
||||
|
||||
if (!$certs) {
|
||||
$certs = $this->retrieveCertsFromLocation(
|
||||
self::FEDERATED_SIGNON_CERT_URL
|
||||
);
|
||||
|
||||
if ($cache) {
|
||||
$cacheItem->set($certs);
|
||||
$cache->save($cacheItem);
|
||||
}
|
||||
}
|
||||
|
||||
if (!isset($certs['keys'])) {
|
||||
throw new InvalidArgumentException(
|
||||
'federated sign-on certs expects "keys" to be set'
|
||||
);
|
||||
}
|
||||
|
||||
return $certs['keys'];
|
||||
}
|
||||
|
||||
private function getJwtService()
|
||||
{
|
||||
$jwtClass = 'JWT';
|
||||
if (class_exists('\Firebase\JWT\JWT')) {
|
||||
$jwtClass = 'Firebase\JWT\JWT';
|
||||
}
|
||||
|
||||
if (property_exists($jwtClass, 'leeway')) {
|
||||
// adds 1 second to JWT leeway
|
||||
// @see https://github.com/google/google-api-php-client/issues/827
|
||||
$jwtClass::$leeway = 1;
|
||||
}
|
||||
|
||||
return new $jwtClass;
|
||||
}
|
||||
|
||||
private function getRsaClass()
|
||||
{
|
||||
if (class_exists('phpseclib\Crypt\RSA')) {
|
||||
return 'phpseclib\Crypt\RSA';
|
||||
}
|
||||
|
||||
return 'Crypt_RSA';
|
||||
}
|
||||
|
||||
private function getBigIntClass()
|
||||
{
|
||||
if (class_exists('phpseclib\Math\BigInteger')) {
|
||||
return 'phpseclib\Math\BigInteger';
|
||||
}
|
||||
|
||||
return 'Math_BigInteger';
|
||||
}
|
||||
|
||||
private function getOpenSslConstant()
|
||||
{
|
||||
if (class_exists('phpseclib\Crypt\RSA')) {
|
||||
return 'phpseclib\Crypt\RSA::MODE_OPENSSL';
|
||||
}
|
||||
|
||||
if (class_exists('Crypt_RSA')) {
|
||||
return 'CRYPT_RSA_MODE_OPENSSL';
|
||||
}
|
||||
|
||||
throw new \Exception('Cannot find RSA class');
|
||||
}
|
||||
|
||||
/**
|
||||
* phpseclib calls "phpinfo" by default, which requires special
|
||||
* whitelisting in the AppEngine VM environment. This function
|
||||
* sets constants to bypass the need for phpseclib to check phpinfo
|
||||
*
|
||||
* @see phpseclib/Math/BigInteger
|
||||
* @see https://github.com/GoogleCloudPlatform/getting-started-php/issues/85
|
||||
*/
|
||||
private function setPhpsecConstants()
|
||||
{
|
||||
if (filter_var(getenv('GAE_VM'), FILTER_VALIDATE_BOOLEAN)) {
|
||||
if (!defined('MATH_BIGINTEGER_OPENSSL_ENABLED')) {
|
||||
define('MATH_BIGINTEGER_OPENSSL_ENABLED', true);
|
||||
}
|
||||
if (!defined('CRYPT_RSA_MODE')) {
|
||||
define('CRYPT_RSA_MODE', constant($this->getOpenSslConstant()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user