See Release Notes
Long Term Support Release
Differences Between: [Versions 400 and 401] [Versions 401 and 402] [Versions 401 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 namespace quizaccess_seb\external; 18 19 defined('MOODLE_INTERNAL') || die(); 20 21 global $CFG; 22 23 use quizaccess_seb\quiz_settings; 24 25 require_once($CFG->libdir . '/externallib.php'); 26 27 /** 28 * PHPUnit tests for external function. 29 * 30 * @package quizaccess_seb 31 * @author Andrew Madden <andrewmadden@catalyst-au.net> 32 * @copyright 2021 Catalyst IT 33 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 34 * @covers \quizaccess_seb\external\validate_quiz_access 35 */ 36 class validate_quiz_access_test extends \advanced_testcase { 37 use \quizaccess_seb_test_helper_trait; 38 39 /** 40 * This method runs before every test. 41 */ 42 public function setUp(): void { 43 parent::setUp(); 44 $this->resetAfterTest(); 45 46 // Generate data objects. 47 $this->course = $this->getDataGenerator()->create_course(); 48 $this->quiz = $this->create_test_quiz($this->course); 49 $this->user = $this->getDataGenerator()->create_user(); 50 $this->getDataGenerator()->enrol_user($this->user->id, $this->course->id, 'student'); 51 $this->setUser($this->user); 52 } 53 54 /** 55 * Bad parameter provider. 56 * 57 * @return array 58 */ 59 public function bad_parameters_provider(): array { 60 return [ 61 'no params' => [ 62 'cmid' => null, 63 'url' => null, 64 'configkey' => null, 65 '/Invalid parameter value detected \(Missing required key in single structure: cmid\)/' 66 ], 67 'no course module id' => [ 68 'cmid' => null, 69 'url' => 'https://www.example.com/moodle', 70 'configkey' => hash('sha256', 'configkey'), 71 '/Invalid parameter value detected \(Missing required key in single structure: cmid\)/' 72 ], 73 'no url' => [ 74 'cmid' => 123, 75 'url' => null, 76 'configkey' => hash('sha256', 'configkey'), 77 '/Invalid parameter value detected \(Missing required key in single structure: url\)/' 78 ], 79 'cmid is not an int' => [ 80 'cmid' => 'test', 81 'url' => 'https://www.example.com/moodle', 82 'configkey' => null, 83 '/Invalid external api parameter: the value is "test", the server was expecting "int" type/' 84 ], 85 'url is not a url' => [ 86 'cmid' => 123, 87 'url' => 123, 88 'configkey' => hash('sha256', 'configkey'), 89 '/Invalid external api parameter: the value is "123", the server was expecting "url" type/' 90 ], 91 ]; 92 } 93 94 /** 95 * Test exception thrown for bad parameters. 96 * 97 * @param mixed $cmid Course module id. 98 * @param mixed $url Page URL. 99 * @param mixed $configkey SEB config key. 100 * @param mixed $messageregex Error message regex to check. 101 * 102 * @dataProvider bad_parameters_provider 103 */ 104 public function test_invalid_parameters($cmid, $url, $configkey, $messageregex) { 105 $params = []; 106 if (!empty($cmid)) { 107 $params['cmid'] = $cmid; 108 } 109 if (!empty($url)) { 110 $params['url'] = $url; 111 } 112 if (!empty($configkey)) { 113 $params['configkey'] = $configkey; 114 } 115 116 $this->expectException(\invalid_parameter_exception::class); 117 $this->expectExceptionMessageMatches($messageregex); 118 \external_api::validate_parameters(validate_quiz_keys::execute_parameters(), $params); 119 } 120 121 /** 122 * Test that the user has permissions to access context. 123 */ 124 public function test_context_is_not_valid_for_user() { 125 // Set user as user not enrolled in course and quiz. 126 $this->user = $this->getDataGenerator()->create_user(); 127 $this->setUser($this->user); 128 129 $this->expectException(\require_login_exception::class); 130 $this->expectExceptionMessage('Course or activity not accessible. (Not enrolled)'); 131 validate_quiz_keys::execute($this->quiz->cmid, 'https://www.example.com/moodle', 'configkey'); 132 } 133 134 /** 135 * Test exception thrown when no key provided. 136 */ 137 public function test_no_keys_provided() { 138 $this->expectException(\invalid_parameter_exception::class); 139 $this->expectExceptionMessage('At least one Safe Exam Browser key must be provided.'); 140 validate_quiz_keys::execute($this->quiz->cmid, 'https://www.example.com/moodle'); 141 } 142 143 /** 144 * Test exception thrown if cmid doesn't match a quiz. 145 */ 146 public function test_quiz_does_not_exist() { 147 $this->setAdminUser(); 148 $forum = $this->getDataGenerator()->create_module('forum', ['course' => $this->course->id]); 149 $this->expectException(\invalid_parameter_exception::class); 150 $this->expectExceptionMessage('Quiz not found matching course module ID: ' . $forum->cmid); 151 validate_quiz_keys::execute($forum->cmid, 'https://www.example.com/moodle', 'configkey'); 152 } 153 154 /** 155 * Test config key is valid. 156 */ 157 public function test_config_key_valid() { 158 $sink = $this->redirectEvents(); 159 // Test settings to populate the quiz. 160 $settings = $this->get_test_settings([ 161 'quizid' => $this->quiz->id, 162 'cmid' => $this->quiz->cmid, 163 ]); 164 $url = 'https://www.example.com/moodle'; 165 166 // Create the quiz settings. 167 $quizsettings = new quiz_settings(0, $settings); 168 $quizsettings->save(); 169 170 $fullconfigkey = hash('sha256', $url . $quizsettings->get_config_key()); 171 $result = validate_quiz_keys::execute($this->quiz->cmid, $url, $fullconfigkey); 172 $this->assertTrue($result['configkey']); 173 $this->assertTrue($result['browserexamkey']); 174 175 $events = $sink->get_events(); 176 $this->assertCount(0, $events); 177 } 178 179 /** 180 * Test config key is not valid. 181 */ 182 public function test_config_key_not_valid() { 183 $sink = $this->redirectEvents(); 184 // Test settings to populate the quiz. 185 $settings = $this->get_test_settings([ 186 'quizid' => $this->quiz->id, 187 'cmid' => $this->quiz->cmid, 188 ]); 189 190 // Create the quiz settings. 191 $quizsettings = new quiz_settings(0, $settings); 192 $quizsettings->save(); 193 194 $result = validate_quiz_keys::execute($this->quiz->cmid, 'https://www.example.com/moodle', 'badconfigkey'); 195 $this->assertFalse($result['configkey']); 196 $this->assertTrue($result['browserexamkey']); 197 $events = $sink->get_events(); 198 $this->assertCount(1, $events); 199 $event = reset($events); 200 $this->assertInstanceOf('\quizaccess_seb\event\access_prevented', $event); 201 $this->assertStringContainsString('Invalid SEB config key', $event->get_description()); 202 } 203 204 /** 205 * Test browser exam key is valid. 206 */ 207 public function test_browser_exam_key_valid() { 208 $sink = $this->redirectEvents(); 209 // Test settings to populate the quiz. 210 $url = 'https://www.example.com/moodle'; 211 $validbrowserexamkey = hash('sha256', 'validbrowserexamkey'); 212 $settings = $this->get_test_settings([ 213 'quizid' => $this->quiz->id, 214 'cmid' => $this->quiz->cmid, 215 'requiresafeexambrowser' => \quizaccess_seb\settings_provider::USE_SEB_CLIENT_CONFIG, 216 'allowedbrowserexamkeys' => $validbrowserexamkey, 217 ]); 218 219 // Create the quiz settings. 220 $quizsettings = new quiz_settings(0, $settings); 221 $quizsettings->save(); 222 223 $fullbrowserexamkey = hash('sha256', $url . $validbrowserexamkey); 224 $result = validate_quiz_keys::execute($this->quiz->cmid, $url, null, $fullbrowserexamkey); 225 $this->assertTrue($result['configkey']); 226 $this->assertTrue($result['browserexamkey']); 227 $events = $sink->get_events(); 228 $this->assertCount(0, $events); 229 } 230 231 /** 232 * Test browser exam key is not valid. 233 */ 234 public function test_browser_exam_key_not_valid() { 235 $sink = $this->redirectEvents(); 236 // Test settings to populate the quiz. 237 $validbrowserexamkey = hash('sha256', 'validbrowserexamkey'); 238 $settings = $this->get_test_settings([ 239 'quizid' => $this->quiz->id, 240 'cmid' => $this->quiz->cmid, 241 'requiresafeexambrowser' => \quizaccess_seb\settings_provider::USE_SEB_CLIENT_CONFIG, 242 'allowedbrowserexamkeys' => $validbrowserexamkey, 243 ]); 244 245 // Create the quiz settings. 246 $quizsettings = new quiz_settings(0, $settings); 247 $quizsettings->save(); 248 249 $result = validate_quiz_keys::execute($this->quiz->cmid, 'https://www.example.com/moodle', null, 250 hash('sha256', 'badbrowserexamkey')); 251 $this->assertTrue($result['configkey']); 252 $this->assertFalse($result['browserexamkey']); 253 $events = $sink->get_events(); 254 $this->assertCount(1, $events); 255 $event = reset($events); 256 $this->assertInstanceOf('\quizaccess_seb\event\access_prevented', $event); 257 $this->assertStringContainsString('Invalid SEB browser key', $event->get_description()); 258 } 259 260 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body