Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 3.11.x will end 14 Nov 2022 (12 months plus 6 months extension).
  • Bug fixes for security issues in 3.11.x will end 13 Nov 2023 (18 months plus 12 months extension).
  • PHP version: minimum PHP 7.3.0 Note: minimum PHP version has increased since Moodle 3.10. PHP 7.4.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  /**
  18   * Contains a helper class for the Shibboleth authentication plugin.
  19   *
  20   * @package    auth_shibboleth
  21   * @copyright  2018 Mark Nelson <markn@moodle.com>
  22   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  23   */
  24  
  25  namespace auth_shibboleth;
  26  
  27  defined('MOODLE_INTERNAL') || die();
  28  
  29  /**
  30   * The helper class for the Shibboleth authentication plugin.
  31   *
  32   * @package    auth_shibboleth
  33   * @copyright  2018 Mark Nelson <markn@moodle.com>
  34   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  35   */
  36  class helper {
  37  
  38      /**
  39       * Delete session of user using file sessions.
  40       *
  41       * @param string $spsessionid SP-provided Shibboleth Session ID
  42       * @return \SoapFault or void if everything was fine
  43       */
  44      public static function logout_file_session($spsessionid) {
  45          global $CFG;
  46  
  47          if (!empty($CFG->session_file_save_path)) {
  48              $dir = $CFG->session_file_save_path;
  49          } else {
  50              $dir = $CFG->dataroot . '/sessions';
  51          }
  52  
  53          if (is_dir($dir)) {
  54              if ($dh = opendir($dir)) {
  55                  // Read all session files.
  56                  while (($file = readdir($dh)) !== false) {
  57                      // Check if it is a file.
  58                      if (is_file($dir.'/'.$file)) {
  59                          // Read session file data.
  60                          $data = file($dir.'/'.$file);
  61                          if (isset($data[0])) {
  62                              $usersession = self::unserializesession($data[0]);
  63                              // Check if we have found session that shall be deleted.
  64                              if (isset($usersession['SESSION']) && isset($usersession['SESSION']->shibboleth_session_id)) {
  65                                  // If there is a match, delete file.
  66                                  if ($usersession['SESSION']->shibboleth_session_id == $spsessionid) {
  67                                      // Delete session file.
  68                                      if (!unlink($dir.'/'.$file)) {
  69                                          return new SoapFault('LogoutError', 'Could not delete Moodle session file.');
  70                                      }
  71                                  }
  72                              }
  73                          }
  74                      }
  75                  }
  76                  closedir($dh);
  77              }
  78          }
  79      }
  80  
  81      /**
  82       * Delete session of user using DB sessions.
  83       *
  84       * @param string $spsessionid SP-provided Shibboleth Session ID
  85       */
  86      public static function logout_db_session($spsessionid) {
  87          global $CFG, $DB;
  88  
  89          $sessions = $DB->get_records_sql(
  90              'SELECT userid, sessdata FROM {sessions} WHERE timemodified > ?',
  91              array(time() - $CFG->sessiontimeout)
  92          );
  93  
  94          foreach ($sessions as $session) {
  95              // Get user session from DB.
  96              $usersession = self::unserializesession(base64_decode($session->sessdata));
  97              if (isset($usersession['SESSION']) && isset($usersession['SESSION']->shibboleth_session_id)) {
  98                  // If there is a match, kill the session.
  99                  if ($usersession['SESSION']->shibboleth_session_id == trim($spsessionid)) {
 100                      // Delete this user's sessions.
 101                      \core\session\manager::kill_user_sessions($session->userid);
 102                  }
 103              }
 104          }
 105      }
 106  
 107      /**
 108       * Unserialize a session string.
 109       *
 110       * @param string $serializedstring
 111       * @return array
 112       */
 113      private static function unserializesession($serializedstring) {
 114          $variables = array();
 115  
 116          $index = 0;
 117  
 118          // Find next delimiter after current index. It's key being the characters between those points.
 119          while ($delimiterpos = strpos($serializedstring, '|', $index)) {
 120              $key = substr($serializedstring, $index, $delimiterpos - $index);
 121  
 122              // Start unserializing immediately after the delimiter. PHP will read as much valid data as possible.
 123              $value = unserialize(substr($serializedstring, $delimiterpos + 1),
 124                  ['allowed_classes' => ['stdClass']]);
 125              $variables[$key] = $value;
 126  
 127              // Advance index beyond the length of the previously captured serialized value.
 128              $index = $delimiterpos + 1 + strlen(serialize($value));
 129          }
 130  
 131          return $variables;
 132      }
 133  }