Search moodle.org's
Developer Documentation

See Release Notes
Long Term Support Release

  • Bug fixes for general core bugs in 3.9.x will end* 10 May 2021 (12 months).
  • Bug fixes for security issues in 3.9.x will end* 8 May 2023 (36 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 39 and 310] [Versions 39 and 311] [Versions 39 and 400] [Versions 39 and 401] [Versions 39 and 402] [Versions 39 and 403]

   1  <?php
   2  // This file is part of Moodle - http://moodle.org/
   3  //
   4  // Moodle is free software: you can redistribute it and/or modify
   5  // it under the terms of the GNU General Public License as published by
   6  // the Free Software Foundation, either version 3 of the License, or
   7  // (at your option) any later version.
   8  //
   9  // Moodle is distributed in the hope that it will be useful,
  10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12  // GNU General Public License for more details.
  13  //
  14  // You should have received a copy of the GNU General Public License
  15  // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
  16  
  17  /**
  18   * Tests for oauth2 apis (\core\oauth2\*).
  19   *
  20   * @package    core
  21   * @copyright  2017 Damyon Wiese
  22   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later.
  23   */
  24  
  25  defined('MOODLE_INTERNAL') || die();
  26  
  27  /**
  28   * Tests for oauth2 apis (\core\oauth2\*).
  29   *
  30   * @package    core
  31   * @copyright  2017 Damyon Wiese
  32   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later.
  33   * @covers     \core\oauth2\api
  34   */
  35  class core_oauth2_testcase extends advanced_testcase {
  36  
  37      /**
  38       * Tests the crud operations on oauth2 issuers.
  39       */
  40      public function test_create_and_delete_standard_issuers() {
  41          $this->resetAfterTest();
  42          $this->setAdminUser();
  43          \core\oauth2\api::create_standard_issuer('google');
  44          \core\oauth2\api::create_standard_issuer('facebook');
  45          \core\oauth2\api::create_standard_issuer('microsoft');
  46          \core\oauth2\api::create_standard_issuer('nextcloud', 'https://dummy.local/nextcloud/');
  47  
  48          $issuers = \core\oauth2\api::get_all_issuers();
  49  
  50          $this->assertEquals($issuers[0]->get('name'), 'Google');
  51          $this->assertEquals($issuers[1]->get('name'), 'Facebook');
  52          $this->assertEquals($issuers[2]->get('name'), 'Microsoft');
  53          $this->assertEquals($issuers[3]->get('name'), 'Nextcloud');
  54  
  55          \core\oauth2\api::move_down_issuer($issuers[0]->get('id'));
  56  
  57          $issuers = \core\oauth2\api::get_all_issuers();
  58  
  59          $this->assertEquals($issuers[0]->get('name'), 'Facebook');
  60          $this->assertEquals($issuers[1]->get('name'), 'Google');
  61          $this->assertEquals($issuers[2]->get('name'), 'Microsoft');
  62          $this->assertEquals($issuers[3]->get('name'), 'Nextcloud');
  63  
  64          \core\oauth2\api::delete_issuer($issuers[1]->get('id'));
  65  
  66          $issuers = \core\oauth2\api::get_all_issuers();
  67  
  68          $this->assertEquals($issuers[0]->get('name'), 'Facebook');
  69          $this->assertEquals($issuers[1]->get('name'), 'Microsoft');
  70          $this->assertEquals($issuers[2]->get('name'), 'Nextcloud');
  71      }
  72  
  73      /**
  74       * Tests the crud operations on oauth2 issuers.
  75       */
  76      public function test_create_nextcloud_without_url() {
  77          $this->resetAfterTest();
  78          $this->setAdminUser();
  79  
  80          $this->expectException(\moodle_exception::class);
  81          \core\oauth2\api::create_standard_issuer('nextcloud');
  82      }
  83  
  84      /**
  85       * Tests we can list and delete each of the persistents related to an issuer.
  86       */
  87      public function test_getters() {
  88          $this->resetAfterTest();
  89          $this->setAdminUser();
  90          $issuer = \core\oauth2\api::create_standard_issuer('microsoft');
  91  
  92          $same = \core\oauth2\api::get_issuer($issuer->get('id'));
  93  
  94          foreach ($same->properties_definition() as $name => $def) {
  95              $this->assertTrue($issuer->get($name) == $same->get($name));
  96          }
  97  
  98          $endpoints = \core\oauth2\api::get_endpoints($issuer);
  99          $same = \core\oauth2\api::get_endpoint($endpoints[0]->get('id'));
 100          $this->assertEquals($endpoints[0]->get('id'), $same->get('id'));
 101          $this->assertEquals($endpoints[0]->get('name'), $same->get('name'));
 102  
 103          $todelete = $endpoints[0];
 104          \core\oauth2\api::delete_endpoint($todelete->get('id'));
 105          $endpoints = \core\oauth2\api::get_endpoints($issuer);
 106          $this->assertNotEquals($endpoints[0]->get('id'), $todelete->get('id'));
 107  
 108          $userfields = \core\oauth2\api::get_user_field_mappings($issuer);
 109          $same = \core\oauth2\api::get_user_field_mapping($userfields[0]->get('id'));
 110          $this->assertEquals($userfields[0]->get('id'), $same->get('id'));
 111  
 112          $todelete = $userfields[0];
 113          \core\oauth2\api::delete_user_field_mapping($todelete->get('id'));
 114          $userfields = \core\oauth2\api::get_user_field_mappings($issuer);
 115          $this->assertNotEquals($userfields[0]->get('id'), $todelete->get('id'));
 116      }
 117  
 118      /**
 119       * Data provider for \core_oauth2_testcase::test_get_system_oauth_client().
 120       *
 121       * @return array
 122       */
 123      public function system_oauth_client_provider() {
 124          return [
 125              [
 126                  (object) [
 127                      'access_token' => 'fdas...',
 128                      'token_type' => 'Bearer',
 129                      'expires_in' => '3600',
 130                      'id_token' => 'llfsd..',
 131                  ], HOURSECS - 10
 132              ],
 133              [
 134                  (object) [
 135                      'access_token' => 'fdas...',
 136                      'token_type' => 'Bearer',
 137                      'id_token' => 'llfsd..',
 138                  ], WEEKSECS
 139              ],
 140          ];
 141      }
 142  
 143      /**
 144       * Tests we can get a logged in oauth client for a system account.
 145       *
 146       * @dataProvider system_oauth_client_provider
 147       * @param stdClass $responsedata The response data to be mocked.
 148       * @param int $expiresin The expected expiration time.
 149       */
 150      public function test_get_system_oauth_client($responsedata, $expiresin) {
 151          $this->resetAfterTest();
 152          $this->setAdminUser();
 153  
 154          $issuer = \core\oauth2\api::create_standard_issuer('microsoft');
 155  
 156          $requiredscopes = \core\oauth2\api::get_system_scopes_for_issuer($issuer);
 157          // Fake a system account.
 158          $data = (object) [
 159              'issuerid' => $issuer->get('id'),
 160              'refreshtoken' => 'abc',
 161              'grantedscopes' => $requiredscopes,
 162              'email' => 'sys@example.com',
 163              'username' => 'sys'
 164          ];
 165          $sys = new \core\oauth2\system_account(0, $data);
 166          $sys->create();
 167  
 168          // Fake a response with an access token.
 169          $response = json_encode($responsedata);
 170          curl::mock_response($response);
 171          $client = \core\oauth2\api::get_system_oauth_client($issuer);
 172          $this->assertTrue($client->is_logged_in());
 173  
 174          // Check token expiry.
 175          $accesstoken = \core\oauth2\access_token::get_record(['issuerid' => $issuer->get('id')]);
 176  
 177          // Get the difference between the actual and expected expiry times.
 178          // They might differ by a couple of seconds depending on the timing when the token gets actually processed.
 179          $expiresdifference = time() + $expiresin - $accesstoken->get('expires');
 180  
 181          // Assert that the actual token expiration is more or less the same as the expected.
 182          $this->assertGreaterThanOrEqual(0, $expiresdifference);
 183          $this->assertLessThanOrEqual(3, $expiresdifference);
 184      }
 185  
 186      /**
 187       * Tests we can enable and disable an issuer.
 188       */
 189      public function test_enable_disable_issuer() {
 190          $this->resetAfterTest();
 191          $this->setAdminUser();
 192  
 193          $issuer = \core\oauth2\api::create_standard_issuer('microsoft');
 194  
 195          $issuerid = $issuer->get('id');
 196  
 197          \core\oauth2\api::enable_issuer($issuerid);
 198          $check = \core\oauth2\api::get_issuer($issuer->get('id'));
 199          $this->assertTrue((boolean)$check->get('enabled'));
 200  
 201          \core\oauth2\api::enable_issuer($issuerid);
 202          $check = \core\oauth2\api::get_issuer($issuer->get('id'));
 203          $this->assertTrue((boolean)$check->get('enabled'));
 204  
 205          \core\oauth2\api::disable_issuer($issuerid);
 206          $check = \core\oauth2\api::get_issuer($issuer->get('id'));
 207          $this->assertFalse((boolean)$check->get('enabled'));
 208  
 209          \core\oauth2\api::enable_issuer($issuerid);
 210          $check = \core\oauth2\api::get_issuer($issuer->get('id'));
 211          $this->assertTrue((boolean)$check->get('enabled'));
 212      }
 213  
 214      /**
 215       * Test the alloweddomains for an issuer.
 216       */
 217      public function test_issuer_alloweddomains() {
 218          $this->resetAfterTest();
 219          $this->setAdminUser();
 220  
 221          $issuer = \core\oauth2\api::create_standard_issuer('microsoft');
 222  
 223          $issuer->set('alloweddomains', '');
 224  
 225          // Anything is allowed when domain is empty.
 226          $this->assertTrue($issuer->is_valid_login_domain(''));
 227          $this->assertTrue($issuer->is_valid_login_domain('a@b'));
 228          $this->assertTrue($issuer->is_valid_login_domain('longer.example@example.com'));
 229  
 230          $issuer->set('alloweddomains', 'example.com');
 231  
 232          // One domain - must match exactly - no substrings etc.
 233          $this->assertFalse($issuer->is_valid_login_domain(''));
 234          $this->assertFalse($issuer->is_valid_login_domain('a@b'));
 235          $this->assertFalse($issuer->is_valid_login_domain('longer.example@example'));
 236          $this->assertTrue($issuer->is_valid_login_domain('longer.example@example.com'));
 237  
 238          $issuer->set('alloweddomains', 'example.com,example.net');
 239          // Multiple domains - must match any exactly - no substrings etc.
 240          $this->assertFalse($issuer->is_valid_login_domain(''));
 241          $this->assertFalse($issuer->is_valid_login_domain('a@b'));
 242          $this->assertFalse($issuer->is_valid_login_domain('longer.example@example'));
 243          $this->assertFalse($issuer->is_valid_login_domain('invalid@email@example.net'));
 244          $this->assertTrue($issuer->is_valid_login_domain('longer.example@example.net'));
 245          $this->assertTrue($issuer->is_valid_login_domain('longer.example@example.com'));
 246  
 247          $issuer->set('alloweddomains', '*.example.com');
 248          // Wildcard.
 249          $this->assertFalse($issuer->is_valid_login_domain(''));
 250          $this->assertFalse($issuer->is_valid_login_domain('a@b'));
 251          $this->assertFalse($issuer->is_valid_login_domain('longer.example@example'));
 252          $this->assertFalse($issuer->is_valid_login_domain('longer.example@example.com'));
 253          $this->assertTrue($issuer->is_valid_login_domain('longer.example@sub.example.com'));
 254      }
 255  
 256  }