Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 4.3.x will end 7 October 2024 (12 months).
  • Bug fixes for security issues in 4.3.x will end 21 April 2025 (18 months).
  • PHP version: minimum PHP 8.0.0 Note: minimum PHP version has increased since Moodle 4.1. PHP 8.2.x is supported too.

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