Search moodle.org's
Developer Documentation

See Release Notes
Long Term Support Release

  • Bug fixes for general core bugs in 4.1.x will end 13 November 2023 (12 months).
  • Bug fixes for security issues in 4.1.x will end 10 November 2025 (36 months).
  • PHP version: minimum PHP 7.4.0 Note: minimum PHP version has increased since Moodle 4.0. PHP 8.0.x is supported too.
   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  namespace enrol_lti\local\ltiadvantage\entity;
  18  
  19  use enrol_lti\local\ltiadvantage\repository\legacy_consumer_repository;
  20  
  21  /**
  22   * Tests for migration_claim.
  23   *
  24   * @package enrol_lti
  25   * @copyright 2021 Jake Dallimore <jrhdallimore@gmail.com>
  26   * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  27   * @coversDefaultClass \enrol_lti\local\ltiadvantage\entity\migration_claim
  28   */
  29  class migration_claim_test extends \advanced_testcase {
  30      /**
  31       * Setup run for each test case.
  32       */
  33      protected function setUp(): void {
  34          $this->resetAfterTest();
  35      }
  36  
  37      /**
  38       * Returns a stub legacy_consumer_repository, allowing tests to verify claims using a predefined secret.
  39       */
  40      protected function get_stub_legacy_consumer_repo() {
  41          $mockedlegacyconsumerrepo = $this->createStub(legacy_consumer_repository::class);
  42          $mockedlegacyconsumerrepo->method('get_consumer_secrets')
  43              ->willReturn(['consumer_secret']);
  44          return $mockedlegacyconsumerrepo;
  45      }
  46  
  47      /**
  48       * Test instantiation and getters of the migration_claim.
  49       *
  50       * @dataProvider migration_claim_provider
  51       * @param array $migrationclaimdata the lti1p1 migration claim.
  52       * @param string $deploymentid string id of the tool deployment.
  53       * @param string $platform string url of the issuer.
  54       * @param string $clientid string id of the client.
  55       * @param string $exp expiry time.
  56       * @param string $nonce nonce.
  57       * @param legacy_consumer_repository $legacyconsumerrepo legacy consumer repo instance.
  58       * @param array $expected array containing expectation data.
  59       * @covers ::__construct
  60       */
  61      public function test_migration_claim(array $migrationclaimdata, string $deploymentid, string $platform,
  62              string $clientid, string $exp, string $nonce, legacy_consumer_repository $legacyconsumerrepo,
  63              array $expected) {
  64  
  65          if (!empty($expected['exception'])) {
  66              $this->expectException($expected['exception']);
  67              $this->expectExceptionMessage($expected['exceptionmessage']);
  68              new migration_claim($migrationclaimdata, $deploymentid, $platform, $clientid, $exp, $nonce,
  69                  $legacyconsumerrepo);
  70          } else {
  71              $migrationclaim = new migration_claim($migrationclaimdata, $deploymentid, $platform, $clientid, $exp,
  72                  $nonce, $legacyconsumerrepo);
  73              $this->assertInstanceOf(migration_claim::class, $migrationclaim);
  74              $this->assertEquals($expected['user_id'], $migrationclaim->get_user_id());
  75              $this->assertEquals($expected['context_id'], $migrationclaim->get_context_id());
  76              $this->assertEquals($expected['tool_consumer_instance_guid'],
  77                  $migrationclaim->get_tool_consumer_instance_guid());
  78              $this->assertEquals($expected['resource_link_id'], $migrationclaim->get_resource_link_id());
  79          }
  80      }
  81  
  82      /**
  83       * Data provider testing migration_claim instantiation.
  84       *
  85       * @return array[] the test case data.
  86       */
  87      public function migration_claim_provider(): array {
  88          // Note: See https://www.imsglobal.org/spec/lti/v1p3/migr#lti-1-1-migration-claim for details regarding the
  89          // correct generation of oauth_consumer_key_sign signature.
  90          return [
  91              'Invalid - missing oauth_consumer_key' => [
  92                  'lti1p1migrationclaim' => [
  93                      'oauth_consumer_key' => '',
  94                      'oauth_consumer_key_sign' => 'abcd',
  95                  ],
  96                  'deploymentid' => 'D12345',
  97                  'platform' => 'https://lms.example.org/',
  98                  'clientid' => 'a1b2c3d4',
  99                  'exp' => '1622612930',
 100                  'nonce' => 'j45j2j5nnjn24544',
 101                  new legacy_consumer_repository(),
 102                  'expected' => [
 103                      'exception' => \coding_exception::class,
 104                      'exceptionmessage' => "Missing 'oauth_consumer_key' property in lti1p1 migration claim."
 105                  ]
 106              ],
 107              'Invalid - missing oauth_consumer_key_sign' => [
 108                  'lti1p1migrationclaim' => [
 109                      'oauth_consumer_key' => 'CONSUMER_1',
 110                      'oauth_consumer_key_sign' => '',
 111                  ],
 112                  'deploymentid' => 'D12345',
 113                  'platform' => 'https://lms.example.org/',
 114                  'clientid' => 'a1b2c3d4',
 115                  'exp' => '1622612930',
 116                  'nonce' => 'j45j2j5nnjn24544',
 117                  new legacy_consumer_repository(),
 118                  'expected' => [
 119                      'exception' => \coding_exception::class,
 120                      'exceptionmessage' => "Missing 'oauth_consumer_key_sign' property in lti1p1 migration claim."
 121                  ]
 122              ],
 123              'Invalid - incorrect oauth_consumer_key_sign' => [
 124                  'lti1p1migrationclaim' => [
 125                      'oauth_consumer_key' => 'CONSUMER_1',
 126                      'oauth_consumer_key_sign' => 'badsignature',
 127                  ],
 128                  'deploymentid' => 'D12345',
 129                  'platform' => 'https://lms.example.org/',
 130                  'clientid' => 'a1b2c3d4',
 131                  'exp' => '1622612930',
 132                  'nonce' => 'j45j2j5nnjn24544',
 133                  new legacy_consumer_repository(),
 134                  'expected' => [
 135                      'exception' => \coding_exception::class,
 136                      'exceptionmessage' => "Invalid 'oauth_consumer_key_sign' signature in lti1p1 claim."
 137                  ]
 138              ],
 139              'Valid - signature valid, map properties not provided' => [
 140                  'lti1p1migrationclaim' => [
 141                      'oauth_consumer_key' => 'CONSUMER_1',
 142                      'oauth_consumer_key_sign' => base64_encode(
 143                          hash_hmac(
 144                              'sha256',
 145                              'CONSUMER_1&D12345&https://lms.example.org/&a1b2c3d4&1622612930&j45j2j5nnjn24544',
 146                              'consumer_secret'
 147                          )
 148                      ),
 149                  ],
 150                  'deploymentid' => 'D12345',
 151                  'platform' => 'https://lms.example.org/',
 152                  'clientid' => 'a1b2c3d4',
 153                  'exp' => '1622612930',
 154                  'nonce' => 'j45j2j5nnjn24544',
 155                  $this->get_stub_legacy_consumer_repo(),
 156                  'expected' => [
 157                      'user_id' => null,
 158                      'context_id' => null,
 159                      'tool_consumer_instance_guid' => null,
 160                      'resource_link_id' => null
 161                  ]
 162              ],
 163              'Valid - signature valid, map properties are provided' => [
 164                  'lti1p1migrationclaim' => [
 165                      'oauth_consumer_key' => 'CONSUMER_1',
 166                      'oauth_consumer_key_sign' => base64_encode(
 167                          hash_hmac(
 168                              'sha256',
 169                              'CONSUMER_1&D12345&https://lms.example.org/&a1b2c3d4&1622612930&j45j2j5nnjn24544',
 170                              'consumer_secret'
 171                          )
 172                      ),
 173                      'user_id' => '24',
 174                      'context_id' => 'd345b',
 175                      'tool_consumer_instance_guid' => '12345-123',
 176                      'resource_link_id' => '4b6fa'
 177                  ],
 178                  'deploymentid' => 'D12345',
 179                  'platform' => 'https://lms.example.org/',
 180                  'clientid' => 'a1b2c3d4',
 181                  'exp' => '1622612930',
 182                  'nonce' => 'j45j2j5nnjn24544',
 183                  $this->get_stub_legacy_consumer_repo(),
 184                  'expected' => [
 185                      'user_id' => '24',
 186                      'context_id' => 'd345b',
 187                      'tool_consumer_instance_guid' => '12345-123',
 188                      'resource_link_id' => '4b6fa'
 189                  ]
 190              ]
 191          ];
 192      }
 193  }