Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 3.10.x will end 8 November 2021 (12 months).
  • Bug fixes for security issues in 3.10.x will end 9 May 2022 (18 months).
  • PHP version: minimum PHP 7.2.0 Note: minimum PHP version has increased since Moodle 3.8. PHP 7.3.x and 7.4.x are supported too.

Differences Between: [Versions 310 and 402] [Versions 310 and 403]

   1  <?php
   2  /*
   3   * Copyright 2012 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  if (!class_exists('Google_Client')) {
  19    require_once dirname(__FILE__) . '/../autoload.php';
  20  }
  21  
  22  /**
  23   * Credentials object used for OAuth 2.0 Signed JWT assertion grants.
  24   */
  25  class Google_Auth_AssertionCredentials
  26  {
  27    const MAX_TOKEN_LIFETIME_SECS = 3600;
  28  
  29    public $serviceAccountName;
  30    public $scopes;
  31    public $privateKey;
  32    public $privateKeyPassword;
  33    public $assertionType;
  34    public $sub;
  35    /**
  36     * @deprecated
  37     * @link http://tools.ietf.org/html/draft-ietf-oauth-json-web-token-06
  38     */
  39    public $prn;
  40    private $useCache;
  41  
  42    /**
  43     * @param $serviceAccountName
  44     * @param $scopes array List of scopes
  45     * @param $privateKey
  46     * @param string $privateKeyPassword
  47     * @param string $assertionType
  48     * @param bool|string $sub The email address of the user for which the
  49     *              application is requesting delegated access.
  50     * @param bool useCache Whether to generate a cache key and allow
  51     *              automatic caching of the generated token.
  52     */
  53    public function __construct(
  54        $serviceAccountName,
  55        $scopes,
  56        $privateKey,
  57        $privateKeyPassword = 'notasecret',
  58        $assertionType = 'http://oauth.net/grant_type/jwt/1.0/bearer',
  59        $sub = false,
  60        $useCache = true
  61    ) {
  62      $this->serviceAccountName = $serviceAccountName;
  63      $this->scopes = is_string($scopes) ? $scopes : implode(' ', $scopes);
  64      $this->privateKey = $privateKey;
  65      $this->privateKeyPassword = $privateKeyPassword;
  66      $this->assertionType = $assertionType;
  67      $this->sub = $sub;
  68      $this->prn = $sub;
  69      $this->useCache = $useCache;
  70    }
  71    
  72    /**
  73     * Generate a unique key to represent this credential.
  74     * @return string
  75     */
  76    public function getCacheKey()
  77    {
  78      if (!$this->useCache) {
  79        return false;
  80      }
  81      $h = $this->sub;
  82      $h .= $this->assertionType;
  83      $h .= $this->privateKey;
  84      $h .= $this->scopes;
  85      $h .= $this->serviceAccountName;
  86      return md5($h);
  87    }
  88  
  89    public function generateAssertion()
  90    {
  91      $now = time();
  92  
  93      $jwtParams = array(
  94            'aud' => Google_Auth_OAuth2::OAUTH2_TOKEN_URI,
  95            'scope' => $this->scopes,
  96            'iat' => $now,
  97            'exp' => $now + self::MAX_TOKEN_LIFETIME_SECS,
  98            'iss' => $this->serviceAccountName,
  99      );
 100  
 101      if ($this->sub !== false) {
 102        $jwtParams['sub'] = $this->sub;
 103      } else if ($this->prn !== false) {
 104        $jwtParams['prn'] = $this->prn;
 105      }
 106  
 107      return $this->makeSignedJwt($jwtParams);
 108    }
 109  
 110    /**
 111     * Creates a signed JWT.
 112     * @param array $payload
 113     * @return string The signed JWT.
 114     */
 115    private function makeSignedJwt($payload)
 116    {
 117      $header = array('typ' => 'JWT', 'alg' => 'RS256');
 118  
 119      $payload = json_encode($payload);
 120      // Handle some overzealous escaping in PHP json that seemed to cause some errors
 121      // with claimsets.
 122      $payload = str_replace('\/', '/', $payload);
 123  
 124      $segments = array(
 125        Google_Utils::urlSafeB64Encode(json_encode($header)),
 126        Google_Utils::urlSafeB64Encode($payload)
 127      );
 128  
 129      $signingInput = implode('.', $segments);
 130      $signer = new Google_Signer_P12($this->privateKey, $this->privateKeyPassword);
 131      $signature = $signer->sign($signingInput);
 132      $segments[] = Google_Utils::urlSafeB64Encode($signature);
 133  
 134      return implode(".", $segments);
 135    }
 136  }