Search moodle.org's
Developer Documentation

See Release Notes

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

Differences Between: [Versions 310 and 402] [Versions 311 and 402] [Versions 39 and 402] [Versions 400 and 402] [Versions 401 and 402]

   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 core;
  18  
  19  /**
  20   * Unit tests for sessionlib.php file.
  21   *
  22   * @package   core
  23   * @category  test
  24   * @author    Petr Skoda <petr.skoda@totaralms.com>
  25   * @copyright 2014 Totara Learning Solutions Ltd {@link http://www.totaralms.com/}
  26   * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  27   */
  28  class sessionlib_test extends \advanced_testcase {
  29  
  30      /**
  31       * @covers ::cron_setup_user
  32       */
  33      public function test_cron_setup_user() {
  34          // This function uses the $GLOBALS super global. Disable the VariableNameLowerCase sniff for this function.
  35          // phpcs:disable moodle.NamingConventions.ValidVariableName.VariableNameLowerCase
  36  
  37          global $PAGE, $USER, $SESSION, $SITE, $CFG;
  38          $this->resetAfterTest();
  39  
  40          // NOTE: this function contains some static caches, let's reset first.
  41          cron_setup_user('reset');
  42          $this->assertDebuggingCalledCount(1);
  43  
  44          $admin = get_admin();
  45          $user1 = $this->getDataGenerator()->create_user();
  46          $user2 = $this->getDataGenerator()->create_user();
  47          $course = $this->getDataGenerator()->create_course();
  48  
  49          cron_setup_user();
  50          $this->assertDebuggingCalledCount(1);
  51          $this->assertSame($admin->id, $USER->id);
  52          $this->assertSame($PAGE->context, \context_course::instance($SITE->id));
  53          $this->assertSame($CFG->timezone, $USER->timezone);
  54          $this->assertSame('', $USER->lang);
  55          $this->assertSame('', $USER->theme);
  56          $SESSION->test1 = true;
  57          $adminsession = $SESSION;
  58          $adminuser = $USER;
  59          $this->assertSame($GLOBALS['SESSION'], $_SESSION['SESSION']);
  60          $this->assertSame($GLOBALS['SESSION'], $SESSION);
  61          $this->assertSame($GLOBALS['USER'], $_SESSION['USER']);
  62          $this->assertSame($GLOBALS['USER'], $USER);
  63  
  64          cron_setup_user(null, $course);
  65          $this->assertDebuggingCalledCount(1);
  66          $this->assertSame($admin->id, $USER->id);
  67          $this->assertSame($PAGE->context, \context_course::instance($course->id));
  68          $this->assertSame($adminsession, $SESSION);
  69          $this->assertSame($GLOBALS['SESSION'], $_SESSION['SESSION']);
  70          $this->assertSame($GLOBALS['SESSION'], $SESSION);
  71          $this->assertSame($GLOBALS['USER'], $_SESSION['USER']);
  72          $this->assertSame($GLOBALS['USER'], $USER);
  73  
  74          cron_setup_user($user1);
  75          $this->assertDebuggingCalledCount(1);
  76          $this->assertSame($user1->id, $USER->id);
  77          $this->assertSame($PAGE->context, \context_course::instance($SITE->id));
  78          $this->assertNotSame($adminsession, $SESSION);
  79          $this->assertObjectNotHasAttribute('test1', $SESSION);
  80          $this->assertEmpty((array)$SESSION);
  81          $usersession1 = $SESSION;
  82          $SESSION->test2 = true;
  83          $this->assertSame($GLOBALS['SESSION'], $_SESSION['SESSION']);
  84          $this->assertSame($GLOBALS['SESSION'], $SESSION);
  85          $this->assertSame($GLOBALS['USER'], $_SESSION['USER']);
  86          $this->assertSame($GLOBALS['USER'], $USER);
  87  
  88          cron_setup_user($user1);
  89          $this->assertDebuggingCalledCount(1);
  90          $this->assertSame($user1->id, $USER->id);
  91          $this->assertSame($PAGE->context, \context_course::instance($SITE->id));
  92          $this->assertNotSame($adminsession, $SESSION);
  93          $this->assertSame($usersession1, $SESSION);
  94          $this->assertSame($GLOBALS['SESSION'], $_SESSION['SESSION']);
  95          $this->assertSame($GLOBALS['SESSION'], $SESSION);
  96          $this->assertSame($GLOBALS['USER'], $_SESSION['USER']);
  97          $this->assertSame($GLOBALS['USER'], $USER);
  98  
  99          cron_setup_user($user2);
 100          $this->assertDebuggingCalledCount(1);
 101          $this->assertSame($user2->id, $USER->id);
 102          $this->assertSame($PAGE->context, \context_course::instance($SITE->id));
 103          $this->assertNotSame($adminsession, $SESSION);
 104          $this->assertNotSame($usersession1, $SESSION);
 105          $this->assertEmpty((array)$SESSION);
 106          $usersession2 = $SESSION;
 107          $usersession2->test3 = true;
 108          $this->assertSame($GLOBALS['SESSION'], $_SESSION['SESSION']);
 109          $this->assertSame($GLOBALS['SESSION'], $SESSION);
 110          $this->assertSame($GLOBALS['USER'], $_SESSION['USER']);
 111          $this->assertSame($GLOBALS['USER'], $USER);
 112  
 113          cron_setup_user($user2, $course);
 114          $this->assertDebuggingCalledCount(1);
 115          $this->assertSame($user2->id, $USER->id);
 116          $this->assertSame($PAGE->context, \context_course::instance($course->id));
 117          $this->assertNotSame($adminsession, $SESSION);
 118          $this->assertNotSame($usersession1, $SESSION);
 119          $this->assertSame($usersession2, $SESSION);
 120          $this->assertSame($GLOBALS['SESSION'], $_SESSION['SESSION']);
 121          $this->assertSame($GLOBALS['SESSION'], $SESSION);
 122          $this->assertSame($GLOBALS['USER'], $_SESSION['USER']);
 123          $this->assertSame($GLOBALS['USER'], $USER);
 124  
 125          cron_setup_user($user1);
 126          $this->assertDebuggingCalledCount(1);
 127          $this->assertSame($user1->id, $USER->id);
 128          $this->assertSame($PAGE->context, \context_course::instance($SITE->id));
 129          $this->assertNotSame($adminsession, $SESSION);
 130          $this->assertNotSame($usersession1, $SESSION);
 131          $this->assertEmpty((array)$SESSION);
 132          $this->assertSame($GLOBALS['SESSION'], $_SESSION['SESSION']);
 133          $this->assertSame($GLOBALS['SESSION'], $SESSION);
 134          $this->assertSame($GLOBALS['USER'], $_SESSION['USER']);
 135          $this->assertSame($GLOBALS['USER'], $USER);
 136  
 137          cron_setup_user();
 138          $this->assertDebuggingCalledCount(1);
 139          $this->assertSame($admin->id, $USER->id);
 140          $this->assertSame($PAGE->context, \context_course::instance($SITE->id));
 141          $this->assertSame($adminsession, $SESSION);
 142          $this->assertSame($adminuser, $USER);
 143          $this->assertSame($GLOBALS['SESSION'], $_SESSION['SESSION']);
 144          $this->assertSame($GLOBALS['SESSION'], $SESSION);
 145          $this->assertSame($GLOBALS['USER'], $_SESSION['USER']);
 146          $this->assertSame($GLOBALS['USER'], $USER);
 147  
 148          cron_setup_user('reset');
 149          $this->assertDebuggingCalledCount(1);
 150          $this->assertSame($GLOBALS['SESSION'], $_SESSION['SESSION']);
 151          $this->assertSame($GLOBALS['SESSION'], $SESSION);
 152          $this->assertSame($GLOBALS['USER'], $_SESSION['USER']);
 153          $this->assertSame($GLOBALS['USER'], $USER);
 154  
 155          cron_setup_user();
 156          $this->assertDebuggingCalledCount(1);
 157          $this->assertNotSame($adminsession, $SESSION);
 158          $this->assertNotSame($adminuser, $USER);
 159          $this->assertSame($GLOBALS['SESSION'], $_SESSION['SESSION']);
 160          $this->assertSame($GLOBALS['SESSION'], $SESSION);
 161          $this->assertSame($GLOBALS['USER'], $_SESSION['USER']);
 162          $this->assertSame($GLOBALS['USER'], $USER);
 163  
 164          // phpcs:enable
 165      }
 166  
 167      /**
 168       * Test provided for secure cookie
 169       *
 170       * @return array of config and secure result
 171       */
 172      public function moodle_cookie_secure_provider() {
 173          return array(
 174              array(
 175                  // Non ssl, not set.
 176                  'config' => array(
 177                      'wwwroot'       => 'http://example.com',
 178                      'sslproxy'      => null,
 179                      'cookiesecure'  => null,
 180                  ),
 181                  'secure' => false,
 182              ),
 183              array(
 184                  // Non ssl, off and ignored.
 185                  'config' => array(
 186                      'wwwroot'       => 'http://example.com',
 187                      'sslproxy'      => null,
 188                      'cookiesecure'  => false,
 189                  ),
 190                  'secure' => false,
 191              ),
 192              array(
 193                  // Non ssl, on and ignored.
 194                  'config' => array(
 195                      'wwwroot'       => 'http://example.com',
 196                      'sslproxy'      => null,
 197                      'cookiesecure'  => true,
 198                  ),
 199                  'secure' => false,
 200              ),
 201              array(
 202                  // SSL via proxy, off.
 203                  'config' => array(
 204                      'wwwroot'       => 'http://example.com',
 205                      'sslproxy'      => true,
 206                      'cookiesecure'  => false,
 207                  ),
 208                  'secure' => false,
 209              ),
 210              array(
 211                  // SSL via proxy, on.
 212                  'config' => array(
 213                      'wwwroot'       => 'http://example.com',
 214                      'sslproxy'      => true,
 215                      'cookiesecure'  => true,
 216                  ),
 217                  'secure' => true,
 218              ),
 219              array(
 220                  // SSL and off.
 221                  'config' => array(
 222                      'wwwroot'       => 'https://example.com',
 223                      'sslproxy'      => null,
 224                      'cookiesecure'  => false,
 225                  ),
 226                  'secure' => false,
 227              ),
 228              array(
 229                  // SSL and on.
 230                  'config' => array(
 231                      'wwwroot'       => 'https://example.com',
 232                      'sslproxy'      => null,
 233                      'cookiesecure'  => true,
 234                  ),
 235                  'secure' => true,
 236              ),
 237          );
 238      }
 239  
 240      /**
 241       * Test for secure cookie
 242       *
 243       * @dataProvider moodle_cookie_secure_provider
 244       *
 245       * @param array $config Array of key value config settings
 246       * @param bool $secure Wether cookies should be secure or not
 247       */
 248      public function test_is_moodle_cookie_secure($config, $secure) {
 249          global $CFG;
 250          $this->resetAfterTest();
 251          foreach ($config as $key => $value) {
 252              $CFG->$key = $value;
 253          }
 254          $this->assertEquals($secure, is_moodle_cookie_secure());
 255      }
 256  
 257      public function test_sesskey() {
 258          global $USER;
 259          $this->resetAfterTest();
 260  
 261          $user = $this->getDataGenerator()->create_user();
 262  
 263          \core\session\manager::init_empty_session();
 264          $this->assertObjectNotHasAttribute('sesskey', $USER);
 265  
 266          $sesskey = sesskey();
 267          $this->assertNotEmpty($sesskey);
 268          $this->assertSame($sesskey, $USER->sesskey);
 269          $this->assertSame($GLOBALS['USER'], $_SESSION['USER']);
 270          $this->assertSame($GLOBALS['USER'], $USER);
 271  
 272          $this->assertSame($sesskey, sesskey());
 273  
 274          // Test incomplete session init - the sesskeys should return random values.
 275          $_SESSION = array();
 276          unset($GLOBALS['USER']);
 277          unset($GLOBALS['SESSION']);
 278  
 279          $this->assertFalse(sesskey());
 280          $this->assertArrayNotHasKey('USER', $GLOBALS);
 281          $this->assertFalse(sesskey());
 282      }
 283  
 284      public function test_confirm_sesskey() {
 285          $this->resetAfterTest();
 286  
 287          $sesskey = sesskey();
 288  
 289          try {
 290              confirm_sesskey();
 291              $this->fail('Exception expected when sesskey not present');
 292          } catch (\moodle_exception $e) {
 293              $this->assertSame('missingparam', $e->errorcode);
 294          }
 295  
 296          $this->assertTrue(confirm_sesskey($sesskey));
 297          $this->assertFalse(confirm_sesskey('blahblah'));
 298  
 299          $_GET['sesskey'] = $sesskey;
 300          $this->assertTrue(confirm_sesskey());
 301  
 302          $_GET['sesskey'] = 'blah';
 303          $this->assertFalse(confirm_sesskey());
 304      }
 305  
 306      public function test_require_sesskey() {
 307          $this->resetAfterTest();
 308  
 309          $sesskey = sesskey();
 310  
 311          try {
 312              require_sesskey();
 313              $this->fail('Exception expected when sesskey not present');
 314          } catch (\moodle_exception $e) {
 315              $this->assertSame('missingparam', $e->errorcode);
 316          }
 317  
 318          $_GET['sesskey'] = $sesskey;
 319          require_sesskey();
 320  
 321          $_GET['sesskey'] = 'blah';
 322          try {
 323              require_sesskey();
 324              $this->fail('Exception expected when sesskey not incorrect');
 325          } catch (\moodle_exception $e) {
 326              $this->assertSame('invalidsesskey', $e->errorcode);
 327          }
 328      }
 329  }