diff options
Diffstat (limited to 'includes/google-api-php-client-master/src/Google/Auth')
8 files changed, 1232 insertions, 0 deletions
diff --git a/includes/google-api-php-client-master/src/Google/Auth/Abstract.php b/includes/google-api-php-client-master/src/Google/Auth/Abstract.php new file mode 100644 index 0000000..4cd7b55 --- /dev/null +++ b/includes/google-api-php-client-master/src/Google/Auth/Abstract.php @@ -0,0 +1,38 @@ +<?php +/* + * Copyright 2010 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. + */ + +if (!class_exists('Google_Client')) { + require_once dirname(__FILE__) . '/../autoload.php'; +} + +/** + * Abstract class for the Authentication in the API client + * @author Chris Chabot <chabotc@google.com> + * + */ +abstract class Google_Auth_Abstract +{ + /** + * An utility function that first calls $this->auth->sign($request) and then + * executes makeRequest() on that signed request. Used for when a request + * should be authenticated + * @param Google_Http_Request $request + * @return Google_Http_Request $request + */ + abstract public function authenticatedRequest(Google_Http_Request $request); + abstract public function sign(Google_Http_Request $request); +} diff --git a/includes/google-api-php-client-master/src/Google/Auth/AppIdentity.php b/includes/google-api-php-client-master/src/Google/Auth/AppIdentity.php new file mode 100644 index 0000000..ba7e720 --- /dev/null +++ b/includes/google-api-php-client-master/src/Google/Auth/AppIdentity.php @@ -0,0 +1,121 @@ +<?php +/* + * Copyright 2014 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. + */ + +/* + * WARNING - this class depends on the Google App Engine PHP library + * which is 5.3 and above only, so if you include this in a PHP 5.2 + * setup or one without 5.3 things will blow up. + */ +use google\appengine\api\app_identity\AppIdentityService; + +if (!class_exists('Google_Client')) { + require_once dirname(__FILE__) . '/../autoload.php'; +} + +/** + * Authentication via the Google App Engine App Identity service. + */ +class Google_Auth_AppIdentity extends Google_Auth_Abstract +{ + const CACHE_PREFIX = "Google_Auth_AppIdentity::"; + private $key = null; + private $client; + private $token = false; + private $tokenScopes = false; + + public function __construct(Google_Client $client, $config = null) + { + $this->client = $client; + } + + /** + * Retrieve an access token for the scopes supplied. + */ + public function authenticateForScope($scopes) + { + if ($this->token && $this->tokenScopes == $scopes) { + return $this->token; + } + + $cacheKey = self::CACHE_PREFIX; + if (is_string($scopes)) { + $cacheKey .= $scopes; + } else if (is_array($scopes)) { + $cacheKey .= implode(":", $scopes); + } + + $this->token = $this->client->getCache()->get($cacheKey); + if (!$this->token) { + $this->retrieveToken($scopes, $cacheKey); + } else if ($this->token['expiration_time'] < time()) { + $this->client->getCache()->delete($cacheKey); + $this->retrieveToken($scopes, $cacheKey); + } + + $this->tokenScopes = $scopes; + return $this->token; + } + + /** + * Retrieve a new access token and store it in cache + * @param mixed $scopes + * @param string $cacheKey + */ + private function retrieveToken($scopes, $cacheKey) + { + $this->token = AppIdentityService::getAccessToken($scopes); + if ($this->token) { + $this->client->getCache()->set( + $cacheKey, + $this->token + ); + } + } + + /** + * Perform an authenticated / signed apiHttpRequest. + * This function takes the apiHttpRequest, calls apiAuth->sign on it + * (which can modify the request in what ever way fits the auth mechanism) + * and then calls apiCurlIO::makeRequest on the signed request + * + * @param Google_Http_Request $request + * @return Google_Http_Request The resulting HTTP response including the + * responseHttpCode, responseHeaders and responseBody. + */ + public function authenticatedRequest(Google_Http_Request $request) + { + $request = $this->sign($request); + return $this->client->getIo()->makeRequest($request); + } + + public function sign(Google_Http_Request $request) + { + if (!$this->token) { + // No token, so nothing to do. + return $request; + } + + $this->client->getLogger()->debug('App Identity authentication'); + + // Add the OAuth2 header to the request + $request->setRequestHeaders( + array('Authorization' => 'Bearer ' . $this->token['access_token']) + ); + + return $request; + } +} diff --git a/includes/google-api-php-client-master/src/Google/Auth/AssertionCredentials.php b/includes/google-api-php-client-master/src/Google/Auth/AssertionCredentials.php new file mode 100644 index 0000000..831d374 --- /dev/null +++ b/includes/google-api-php-client-master/src/Google/Auth/AssertionCredentials.php @@ -0,0 +1,136 @@ +<?php +/* + * Copyright 2012 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. + */ + +if (!class_exists('Google_Client')) { + require_once dirname(__FILE__) . '/../autoload.php'; +} + +/** + * Credentials object used for OAuth 2.0 Signed JWT assertion grants. + */ +class Google_Auth_AssertionCredentials +{ + const MAX_TOKEN_LIFETIME_SECS = 3600; + + public $serviceAccountName; + public $scopes; + public $privateKey; + public $privateKeyPassword; + public $assertionType; + public $sub; + /** + * @deprecated + * @link http://tools.ietf.org/html/draft-ietf-oauth-json-web-token-06 + */ + public $prn; + private $useCache; + + /** + * @param $serviceAccountName + * @param $scopes array List of scopes + * @param $privateKey + * @param string $privateKeyPassword + * @param string $assertionType + * @param bool|string $sub The email address of the user for which the + * application is requesting delegated access. + * @param bool useCache Whether to generate a cache key and allow + * automatic caching of the generated token. + */ + public function __construct( + $serviceAccountName, + $scopes, + $privateKey, + $privateKeyPassword = 'notasecret', + $assertionType = 'http://oauth.net/grant_type/jwt/1.0/bearer', + $sub = false, + $useCache = true + ) { + $this->serviceAccountName = $serviceAccountName; + $this->scopes = is_string($scopes) ? $scopes : implode(' ', $scopes); + $this->privateKey = $privateKey; + $this->privateKeyPassword = $privateKeyPassword; + $this->assertionType = $assertionType; + $this->sub = $sub; + $this->prn = $sub; + $this->useCache = $useCache; + } + + /** + * Generate a unique key to represent this credential. + * @return string + */ + public function getCacheKey() + { + if (!$this->useCache) { + return false; + } + $h = $this->sub; + $h .= $this->assertionType; + $h .= $this->privateKey; + $h .= $this->scopes; + $h .= $this->serviceAccountName; + return md5($h); + } + + public function generateAssertion() + { + $now = time(); + + $jwtParams = array( + 'aud' => Google_Auth_OAuth2::OAUTH2_TOKEN_URI, + 'scope' => $this->scopes, + 'iat' => $now, + 'exp' => $now + self::MAX_TOKEN_LIFETIME_SECS, + 'iss' => $this->serviceAccountName, + ); + + if ($this->sub !== false) { + $jwtParams['sub'] = $this->sub; + } else if ($this->prn !== false) { + $jwtParams['prn'] = $this->prn; + } + + return $this->makeSignedJwt($jwtParams); + } + + /** + * Creates a signed JWT. + * @param array $payload + * @return string The signed JWT. + */ + private function makeSignedJwt($payload) + { + $header = array('typ' => 'JWT', 'alg' => 'RS256'); + + $payload = json_encode($payload); + // Handle some overzealous escaping in PHP json that seemed to cause some errors + // with claimsets. + $payload = str_replace('\/', '/', $payload); + + $segments = array( + Google_Utils::urlSafeB64Encode(json_encode($header)), + Google_Utils::urlSafeB64Encode($payload) + ); + + $signingInput = implode('.', $segments); + $signer = new Google_Signer_P12($this->privateKey, $this->privateKeyPassword); + $signature = $signer->sign($signingInput); + $segments[] = Google_Utils::urlSafeB64Encode($signature); + + return implode(".", $segments); + } +} diff --git a/includes/google-api-php-client-master/src/Google/Auth/ComputeEngine.php b/includes/google-api-php-client-master/src/Google/Auth/ComputeEngine.php new file mode 100644 index 0000000..88ff6ff --- /dev/null +++ b/includes/google-api-php-client-master/src/Google/Auth/ComputeEngine.php @@ -0,0 +1,146 @@ +<?php +/* + * Copyright 2014 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. + */ + +if (!class_exists('Google_Client')) { + require_once dirname(__FILE__) . '/../autoload.php'; +} + +/** + * Authentication via built-in Compute Engine service accounts. + * The instance must be pre-configured with a service account + * and the appropriate scopes. + * @author Jonathan Parrott <jon.wayne.parrott@gmail.com> + */ +class Google_Auth_ComputeEngine extends Google_Auth_Abstract +{ + const METADATA_AUTH_URL = + 'http://metadata/computeMetadata/v1/instance/service-accounts/default/token'; + private $client; + private $token; + + public function __construct(Google_Client $client, $config = null) + { + $this->client = $client; + } + + /** + * Perform an authenticated / signed apiHttpRequest. + * This function takes the apiHttpRequest, calls apiAuth->sign on it + * (which can modify the request in what ever way fits the auth mechanism) + * and then calls apiCurlIO::makeRequest on the signed request + * + * @param Google_Http_Request $request + * @return Google_Http_Request The resulting HTTP response including the + * responseHttpCode, responseHeaders and responseBody. + */ + public function authenticatedRequest(Google_Http_Request $request) + { + $request = $this->sign($request); + return $this->client->getIo()->makeRequest($request); + } + + /** + * @param string $token + * @throws Google_Auth_Exception + */ + public function setAccessToken($token) + { + $token = json_decode($token, true); + if ($token == null) { + throw new Google_Auth_Exception('Could not json decode the token'); + } + if (! isset($token['access_token'])) { + throw new Google_Auth_Exception("Invalid token format"); + } + $token['created'] = time(); + $this->token = $token; + } + + public function getAccessToken() + { + return json_encode($this->token); + } + + /** + * Acquires a new access token from the compute engine metadata server. + * @throws Google_Auth_Exception + */ + public function acquireAccessToken() + { + $request = new Google_Http_Request( + self::METADATA_AUTH_URL, + 'GET', + array( + 'Metadata-Flavor' => 'Google' + ) + ); + $request->disableGzip(); + $response = $this->client->getIo()->makeRequest($request); + + if ($response->getResponseHttpCode() == 200) { + $this->setAccessToken($response->getResponseBody()); + $this->token['created'] = time(); + return $this->getAccessToken(); + } else { + throw new Google_Auth_Exception( + sprintf( + "Error fetching service account access token, message: '%s'", + $response->getResponseBody() + ), + $response->getResponseHttpCode() + ); + } + } + + /** + * Include an accessToken in a given apiHttpRequest. + * @param Google_Http_Request $request + * @return Google_Http_Request + * @throws Google_Auth_Exception + */ + public function sign(Google_Http_Request $request) + { + if ($this->isAccessTokenExpired()) { + $this->acquireAccessToken(); + } + + $this->client->getLogger()->debug('Compute engine service account authentication'); + + $request->setRequestHeaders( + array('Authorization' => 'Bearer ' . $this->token['access_token']) + ); + + return $request; + } + + /** + * Returns if the access_token is expired. + * @return bool Returns True if the access_token is expired. + */ + public function isAccessTokenExpired() + { + if (!$this->token || !isset($this->token['created'])) { + return true; + } + + // If the token is set to expire in the next 30 seconds. + $expired = ($this->token['created'] + + ($this->token['expires_in'] - 30)) < time(); + + return $expired; + } +} diff --git a/includes/google-api-php-client-master/src/Google/Auth/Exception.php b/includes/google-api-php-client-master/src/Google/Auth/Exception.php new file mode 100644 index 0000000..e4b75c1 --- /dev/null +++ b/includes/google-api-php-client-master/src/Google/Auth/Exception.php @@ -0,0 +1,24 @@ +<?php +/* + * Copyright 2013 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. + */ + +if (!class_exists('Google_Client')) { + require_once dirname(__FILE__) . '/../autoload.php'; +} + +class Google_Auth_Exception extends Google_Exception +{ +} diff --git a/includes/google-api-php-client-master/src/Google/Auth/LoginTicket.php b/includes/google-api-php-client-master/src/Google/Auth/LoginTicket.php new file mode 100644 index 0000000..371b3ce --- /dev/null +++ b/includes/google-api-php-client-master/src/Google/Auth/LoginTicket.php @@ -0,0 +1,71 @@ +<?php +/* + * Copyright 2011 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. + */ + +if (!class_exists('Google_Client')) { + require_once dirname(__FILE__) . '/../autoload.php'; +} + +/** + * Class to hold information about an authenticated login. + * + * @author Brian Eaton <beaton@google.com> + */ +class Google_Auth_LoginTicket +{ + const USER_ATTR = "sub"; + + // Information from id token envelope. + private $envelope; + + // Information from id token payload. + private $payload; + + /** + * Creates a user based on the supplied token. + * + * @param string $envelope Header from a verified authentication token. + * @param string $payload Information from a verified authentication token. + */ + public function __construct($envelope, $payload) + { + $this->envelope = $envelope; + $this->payload = $payload; + } + + /** + * Returns the numeric identifier for the user. + * @throws Google_Auth_Exception + * @return + */ + public function getUserId() + { + if (array_key_exists(self::USER_ATTR, $this->payload)) { + return $this->payload[self::USER_ATTR]; + } + throw new Google_Auth_Exception("No user_id in token"); + } + + /** + * Returns attributes from the login ticket. This can contain + * various information about the user session. + * @return array + */ + public function getAttributes() + { + return array("envelope" => $this->envelope, "payload" => $this->payload); + } +} diff --git a/includes/google-api-php-client-master/src/Google/Auth/OAuth2.php b/includes/google-api-php-client-master/src/Google/Auth/OAuth2.php new file mode 100644 index 0000000..5206e3b --- /dev/null +++ b/includes/google-api-php-client-master/src/Google/Auth/OAuth2.php @@ -0,0 +1,632 @@ +<?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. + */ + +if (!class_exists('Google_Client')) { + require_once dirname(__FILE__) . '/../autoload.php'; +} + +/** + * Authentication class that deals with the OAuth 2 web-server authentication flow + * + */ +class Google_Auth_OAuth2 extends Google_Auth_Abstract +{ + const OAUTH2_REVOKE_URI = 'https://accounts.google.com/o/oauth2/revoke'; + const OAUTH2_TOKEN_URI = 'https://accounts.google.com/o/oauth2/token'; + const OAUTH2_AUTH_URL = 'https://accounts.google.com/o/oauth2/auth'; + const CLOCK_SKEW_SECS = 300; // five minutes in seconds + const AUTH_TOKEN_LIFETIME_SECS = 300; // five minutes in seconds + const MAX_TOKEN_LIFETIME_SECS = 86400; // one day in seconds + const OAUTH2_ISSUER = 'accounts.google.com'; + + /** @var Google_Auth_AssertionCredentials $assertionCredentials */ + private $assertionCredentials; + + /** + * @var string The state parameters for CSRF and other forgery protection. + */ + private $state; + + /** + * @var array The token bundle. + */ + private $token = array(); + + /** + * @var Google_Client the base client + */ + private $client; + + /** + * Instantiates the class, but does not initiate the login flow, leaving it + * to the discretion of the caller. + */ + public function __construct(Google_Client $client) + { + $this->client = $client; + } + + /** + * Perform an authenticated / signed apiHttpRequest. + * This function takes the apiHttpRequest, calls apiAuth->sign on it + * (which can modify the request in what ever way fits the auth mechanism) + * and then calls apiCurlIO::makeRequest on the signed request + * + * @param Google_Http_Request $request + * @return Google_Http_Request The resulting HTTP response including the + * responseHttpCode, responseHeaders and responseBody. + */ + public function authenticatedRequest(Google_Http_Request $request) + { + $request = $this->sign($request); + return $this->client->getIo()->makeRequest($request); + } + + /** + * @param string $code + * @throws Google_Auth_Exception + * @return string + */ + public function authenticate($code) + { + if (strlen($code) == 0) { + throw new Google_Auth_Exception("Invalid code"); + } + + // We got here from the redirect from a successful authorization grant, + // fetch the access token + $request = new Google_Http_Request( + self::OAUTH2_TOKEN_URI, + 'POST', + array(), + array( + 'code' => $code, + 'grant_type' => 'authorization_code', + 'redirect_uri' => $this->client->getClassConfig($this, 'redirect_uri'), + 'client_id' => $this->client->getClassConfig($this, 'client_id'), + 'client_secret' => $this->client->getClassConfig($this, 'client_secret') + ) + ); + $request->disableGzip(); + $response = $this->client->getIo()->makeRequest($request); + + if ($response->getResponseHttpCode() == 200) { + $this->setAccessToken($response->getResponseBody()); + $this->token['created'] = time(); + return $this->getAccessToken(); + } else { + $decodedResponse = json_decode($response->getResponseBody(), true); + if ($decodedResponse != null && $decodedResponse['error']) { + $errorText = $decodedResponse['error']; + if (isset($decodedResponse['error_description'])) { + $errorText .= ": " . $decodedResponse['error_description']; + } + } + throw new Google_Auth_Exception( + sprintf( + "Error fetching OAuth2 access token, message: '%s'", + $errorText + ), + $response->getResponseHttpCode() + ); + } + } + + /** + * Create a URL to obtain user authorization. + * The authorization endpoint allows the user to first + * authenticate, and then grant/deny the access request. + * @param string $scope The scope is expressed as a list of space-delimited strings. + * @return string + */ + public function createAuthUrl($scope) + { + $params = array( + 'response_type' => 'code', + 'redirect_uri' => $this->client->getClassConfig($this, 'redirect_uri'), + 'client_id' => $this->client->getClassConfig($this, 'client_id'), + 'scope' => $scope, + 'access_type' => $this->client->getClassConfig($this, 'access_type'), + ); + + // Prefer prompt to approval prompt. + if ($this->client->getClassConfig($this, 'prompt')) { + $params = $this->maybeAddParam($params, 'prompt'); + } else { + $params = $this->maybeAddParam($params, 'approval_prompt'); + } + $params = $this->maybeAddParam($params, 'login_hint'); + $params = $this->maybeAddParam($params, 'hd'); + $params = $this->maybeAddParam($params, 'openid.realm'); + $params = $this->maybeAddParam($params, 'include_granted_scopes'); + + // If the list of scopes contains plus.login, add request_visible_actions + // to auth URL. + $rva = $this->client->getClassConfig($this, 'request_visible_actions'); + if (strpos($scope, 'plus.login') && strlen($rva) > 0) { + $params['request_visible_actions'] = $rva; + } + + if (isset($this->state)) { + $params['state'] = $this->state; + } + + return self::OAUTH2_AUTH_URL . "?" . http_build_query($params, '', '&'); + } + + /** + * @param string $token + * @throws Google_Auth_Exception + */ + public function setAccessToken($token) + { + $token = json_decode($token, true); + if ($token == null) { + throw new Google_Auth_Exception('Could not json decode the token'); + } + if (! isset($token['access_token'])) { + throw new Google_Auth_Exception("Invalid token format"); + } + $this->token = $token; + } + + public function getAccessToken() + { + return json_encode($this->token); + } + + public function getRefreshToken() + { + if (array_key_exists('refresh_token', $this->token)) { + return $this->token['refresh_token']; + } else { + return null; + } + } + + public function setState($state) + { + $this->state = $state; + } + + public function setAssertionCredentials(Google_Auth_AssertionCredentials $creds) + { + $this->assertionCredentials = $creds; + } + + /** + * Include an accessToken in a given apiHttpRequest. + * @param Google_Http_Request $request + * @return Google_Http_Request + * @throws Google_Auth_Exception + */ + public function sign(Google_Http_Request $request) + { + // add the developer key to the request before signing it + if ($this->client->getClassConfig($this, 'developer_key')) { + $request->setQueryParam('key', $this->client->getClassConfig($this, 'developer_key')); + } + + // Cannot sign the request without an OAuth access token. + if (null == $this->token && null == $this->assertionCredentials) { + return $request; + } + + // Check if the token is set to expire in the next 30 seconds + // (or has already expired). + if ($this->isAccessTokenExpired()) { + if ($this->assertionCredentials) { + $this->refreshTokenWithAssertion(); + } else { + $this->client->getLogger()->debug('OAuth2 access token expired'); + if (! array_key_exists('refresh_token', $this->token)) { + $error = "The OAuth 2.0 access token has expired," + ." and a refresh token is not available. Refresh tokens" + ." are not returned for responses that were auto-approved."; + + $this->client->getLogger()->error($error); + throw new Google_Auth_Exception($error); + } + $this->refreshToken($this->token['refresh_token']); + } + } + + $this->client->getLogger()->debug('OAuth2 authentication'); + + // Add the OAuth2 header to the request + $request->setRequestHeaders( + array('Authorization' => 'Bearer ' . $this->token['access_token']) + ); + + return $request; + } + + /** + * Fetches a fresh access token with the given refresh token. + * @param string $refreshToken + * @return void + */ + public function refreshToken($refreshToken) + { + $this->refreshTokenRequest( + array( + 'client_id' => $this->client->getClassConfig($this, 'client_id'), + 'client_secret' => $this->client->getClassConfig($this, 'client_secret'), + 'refresh_token' => $refreshToken, + 'grant_type' => 'refresh_token' + ) + ); + } + + /** + * Fetches a fresh access token with a given assertion token. + * @param Google_Auth_AssertionCredentials $assertionCredentials optional. + * @return void + */ + public function refreshTokenWithAssertion($assertionCredentials = null) + { + if (!$assertionCredentials) { + $assertionCredentials = $this->assertionCredentials; + } + + $cacheKey = $assertionCredentials->getCacheKey(); + + if ($cacheKey) { + // We can check whether we have a token available in the + // cache. If it is expired, we can retrieve a new one from + // the assertion. + $token = $this->client->getCache()->get($cacheKey); + if ($token) { + $this->setAccessToken($token); + } + if (!$this->isAccessTokenExpired()) { + return; + } + } + + $this->client->getLogger()->debug('OAuth2 access token expired'); + $this->refreshTokenRequest( + array( + 'grant_type' => 'assertion', + 'assertion_type' => $assertionCredentials->assertionType, + 'assertion' => $assertionCredentials->generateAssertion(), + ) + ); + + if ($cacheKey) { + // Attempt to cache the token. + $this->client->getCache()->set( + $cacheKey, + $this->getAccessToken() + ); + } + } + + private function refreshTokenRequest($params) + { + if (isset($params['assertion'])) { + $this->client->getLogger()->info( + 'OAuth2 access token refresh with Signed JWT assertion grants.' + ); + } else { + $this->client->getLogger()->info('OAuth2 access token refresh'); + } + + $http = new Google_Http_Request( + self::OAUTH2_TOKEN_URI, + 'POST', + array(), + $params + ); + $http->disableGzip(); + $request = $this->client->getIo()->makeRequest($http); + + $code = $request->getResponseHttpCode(); + $body = $request->getResponseBody(); + if (200 == $code) { + $token = json_decode($body, true); + if ($token == null) { + throw new Google_Auth_Exception("Could not json decode the access token"); + } + + if (! isset($token['access_token']) || ! isset($token['expires_in'])) { + throw new Google_Auth_Exception("Invalid token format"); + } + + if (isset($token['id_token'])) { + $this->token['id_token'] = $token['id_token']; + } + $this->token['access_token'] = $token['access_token']; + $this->token['expires_in'] = $token['expires_in']; + $this->token['created'] = time(); + } else { + throw new Google_Auth_Exception("Error refreshing the OAuth2 token, message: '$body'", $code); + } + } + + /** + * Revoke an OAuth2 access token or refresh token. This method will revoke the current access + * token, if a token isn't provided. + * @throws Google_Auth_Exception + * @param string|null $token The token (access token or a refresh token) that should be revoked. + * @return boolean Returns True if the revocation was successful, otherwise False. + */ + public function revokeToken($token = null) + { + if (!$token) { + if (!$this->token) { + // Not initialized, no token to actually revoke + return false; + } elseif (array_key_exists('refresh_token', $this->token)) { + $token = $this->token['refresh_token']; + } else { + $token = $this->token['access_token']; + } + } + $request = new Google_Http_Request( + self::OAUTH2_REVOKE_URI, + 'POST', + array(), + "token=$token" + ); + $request->disableGzip(); + $response = $this->client->getIo()->makeRequest($request); + $code = $response->getResponseHttpCode(); + if ($code == 200) { + $this->token = null; + return true; + } + + return false; + } + + /** + * Returns if the access_token is expired. + * @return bool Returns True if the access_token is expired. + */ + public function isAccessTokenExpired() + { + if (!$this->token || !isset($this->token['created'])) { + return true; + } + + // If the token is set to expire in the next 30 seconds. + $expired = ($this->token['created'] + + ($this->token['expires_in'] - 30)) < time(); + + return $expired; + } + + // 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() + { + return $this->retrieveCertsFromLocation( + $this->client->getClassConfig($this, 'federated_signon_certs_url') + ); + } + + /** + * Retrieve and cache a certificates file. + * + * @param $url string location + * @throws Google_Auth_Exception + * @return array certificates + */ + public function retrieveCertsFromLocation($url) + { + // If we're retrieving a local file, just grab it. + if ("http" != substr($url, 0, 4)) { + $file = file_get_contents($url); + if ($file) { + return json_decode($file, true); + } else { + throw new Google_Auth_Exception( + "Failed to retrieve verification certificates: '" . + $url . "'." + ); + } + } + + // This relies on makeRequest caching certificate responses. + $request = $this->client->getIo()->makeRequest( + new Google_Http_Request( + $url + ) + ); + if ($request->getResponseHttpCode() == 200) { + $certs = json_decode($request->getResponseBody(), true); + if ($certs) { + return $certs; + } + } + throw new Google_Auth_Exception( + "Failed to retrieve verification certificates: '" . + $request->getResponseBody() . "'.", + $request->getResponseHttpCode() + ); + } + + /** + * 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 $id_token + * @param $audience + * @return Google_Auth_LoginTicket + */ + public function verifyIdToken($id_token = null, $audience = null) + { + if (!$id_token) { + $id_token = $this->token['id_token']; + } + $certs = $this->getFederatedSignonCerts(); + if (!$audience) { + $audience = $this->client->getClassConfig($this, 'client_id'); + } + + return $this->verifySignedJwtWithCerts($id_token, $certs, $audience, self::OAUTH2_ISSUER); + } + + /** + * Verifies the id token, returns the verified token contents. + * + * @param $jwt string the token + * @param $certs array of certificates + * @param $required_audience string the expected consumer of the token + * @param [$issuer] the expected issues, defaults to Google + * @param [$max_expiry] the max lifetime of a token, defaults to MAX_TOKEN_LIFETIME_SECS + * @throws Google_Auth_Exception + * @return mixed token information if valid, false if not + */ + public function verifySignedJwtWithCerts( + $jwt, + $certs, + $required_audience, + $issuer = null, + $max_expiry = null + ) { + if (!$max_expiry) { + // Set the maximum time we will accept a token for. + $max_expiry = self::MAX_TOKEN_LIFETIME_SECS; + } + + $segments = explode(".", $jwt); + if (count($segments) != 3) { + throw new Google_Auth_Exception("Wrong number of segments in token: $jwt"); + } + $signed = $segments[0] . "." . $segments[1]; + $signature = Google_Utils::urlSafeB64Decode($segments[2]); + + // Parse envelope. + $envelope = json_decode(Google_Utils::urlSafeB64Decode($segments[0]), true); + if (!$envelope) { + throw new Google_Auth_Exception("Can't parse token envelope: " . $segments[0]); + } + + // Parse token + $json_body = Google_Utils::urlSafeB64Decode($segments[1]); + $payload = json_decode($json_body, true); + if (!$payload) { + throw new Google_Auth_Exception("Can't parse token payload: " . $segments[1]); + } + + // Check signature + $verified = false; + foreach ($certs as $keyName => $pem) { + $public_key = new Google_Verifier_Pem($pem); + if ($public_key->verify($signed, $signature)) { + $verified = true; + break; + } + } + + if (!$verified) { + throw new Google_Auth_Exception("Invalid token signature: $jwt"); + } + + // Check issued-at timestamp + $iat = 0; + if (array_key_exists("iat", $payload)) { + $iat = $payload["iat"]; + } + if (!$iat) { + throw new Google_Auth_Exception("No issue time in token: $json_body"); + } + $earliest = $iat - self::CLOCK_SKEW_SECS; + + // Check expiration timestamp + $now = time(); + $exp = 0; + if (array_key_exists("exp", $payload)) { + $exp = $payload["exp"]; + } + if (!$exp) { + throw new Google_Auth_Exception("No expiration time in token: $json_body"); + } + if ($exp >= $now + $max_expiry) { + throw new Google_Auth_Exception( + sprintf("Expiration time too far in future: %s", $json_body) + ); + } + + $latest = $exp + self::CLOCK_SKEW_SECS; + if ($now < $earliest) { + throw new Google_Auth_Exception( + sprintf( + "Token used too early, %s < %s: %s", + $now, + $earliest, + $json_body + ) + ); + } + if ($now > $latest) { + throw new Google_Auth_Exception( + sprintf( + "Token used too late, %s > %s: %s", + $now, + $latest, + $json_body + ) + ); + } + + $iss = $payload['iss']; + if ($issuer && $iss != $issuer) { + throw new Google_Auth_Exception( + sprintf( + "Invalid issuer, %s != %s: %s", + $iss, + $issuer, + $json_body + ) + ); + } + + // Check audience + $aud = $payload["aud"]; + if ($aud != $required_audience) { + throw new Google_Auth_Exception( + sprintf( + "Wrong recipient, %s != %s:", + $aud, + $required_audience, + $json_body + ) + ); + } + + // All good. + return new Google_Auth_LoginTicket($envelope, $payload); + } + + /** + * Add a parameter to the auth params if not empty string. + */ + private function maybeAddParam($params, $name) + { + $param = $this->client->getClassConfig($this, $name); + if ($param != '') { + $params[$name] = $param; + } + return $params; + } +} diff --git a/includes/google-api-php-client-master/src/Google/Auth/Simple.php b/includes/google-api-php-client-master/src/Google/Auth/Simple.php new file mode 100644 index 0000000..69476c7 --- /dev/null +++ b/includes/google-api-php-client-master/src/Google/Auth/Simple.php @@ -0,0 +1,64 @@ +<?php +/* + * Copyright 2010 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. + */ + +if (!class_exists('Google_Client')) { + require_once dirname(__FILE__) . '/../autoload.php'; +} + +/** + * Simple API access implementation. Can either be used to make requests + * completely unauthenticated, or by using a Simple API Access developer + * key. + */ +class Google_Auth_Simple extends Google_Auth_Abstract +{ + private $key = null; + private $client; + + public function __construct(Google_Client $client, $config = null) + { + $this->client = $client; + } + + /** + * Perform an authenticated / signed apiHttpRequest. + * This function takes the apiHttpRequest, calls apiAuth->sign on it + * (which can modify the request in what ever way fits the auth mechanism) + * and then calls apiCurlIO::makeRequest on the signed request + * + * @param Google_Http_Request $request + * @return Google_Http_Request The resulting HTTP response including the + * responseHttpCode, responseHeaders and responseBody. + */ + public function authenticatedRequest(Google_Http_Request $request) + { + $request = $this->sign($request); + return $this->io->makeRequest($request); + } + + public function sign(Google_Http_Request $request) + { + $key = $this->client->getClassConfig($this, 'developer_key'); + if ($key) { + $this->client->getLogger()->debug( + 'Simple API Access developer key authentication' + ); + $request->setQueryParam('key', $key); + } + return $request; + } +} |