[ Index ]

PHP Cross Reference of Unnamed Project

title

Body

[close]

/auth/shibboleth/ -> auth.php (source)

   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   * Authentication Plugin: Shibboleth Authentication
  19   * Authentication using Shibboleth.
  20   *
  21   * Distributed under GPL (c)Markus Hagman 2004-2006
  22   *
  23   * @package auth_shibboleth
  24   * @author Martin Dougiamas
  25   * @author Lukas Haemmerle
  26   * @license http://www.gnu.org/copyleft/gpl.html GNU Public License
  27   */
  28  
  29  defined('MOODLE_INTERNAL') || die();
  30  
  31  require_once($CFG->libdir.'/authlib.php');
  32  
  33  /**
  34   * Shibboleth authentication plugin.
  35   */
  36  class auth_plugin_shibboleth extends auth_plugin_base {
  37  
  38      /**
  39       * Constructor.
  40       */
  41      public function __construct() {
  42          $this->authtype = 'shibboleth';
  43          $this->config = get_config('auth/shibboleth');
  44      }
  45  
  46      /**
  47       * Old syntax of class constructor. Deprecated in PHP7.
  48       *
  49       * @deprecated since Moodle 3.1
  50       */
  51      public function auth_plugin_shibboleth() {
  52          debugging('Use of class name as constructor is deprecated', DEBUG_DEVELOPER);
  53          self::__construct();
  54      }
  55  
  56      /**
  57       * Returns true if the username and password work and false if they are
  58       * wrong or don't exist.
  59       *
  60       * @param string $username The username (with system magic quotes)
  61       * @param string $password The password (with system magic quotes)
  62       * @return bool Authentication success or failure.
  63       */
  64      function user_login($username, $password) {
  65         global $SESSION;
  66  
  67          // If we are in the shibboleth directory then we trust the server var
  68          if (!empty($_SERVER[$this->config->user_attribute])) {
  69              // Associate Shibboleth session with user for SLO preparation
  70              $sessionkey = '';
  71              if (isset($_SERVER['Shib-Session-ID'])){
  72                  // This is only available for Shibboleth 2.x SPs
  73                  $sessionkey = $_SERVER['Shib-Session-ID'];
  74              } else {
  75                  // Try to find out using the user's cookie
  76                  foreach ($_COOKIE as $name => $value){
  77                      if (preg_match('/_shibsession_/i', $name)){
  78                          $sessionkey = $value;
  79                      }
  80                  }
  81              }
  82  
  83              // Set shibboleth session ID for logout
  84              $SESSION->shibboleth_session_id  = $sessionkey;
  85  
  86              return (strtolower($_SERVER[$this->config->user_attribute]) == strtolower($username));
  87          } else {
  88              // If we are not, the user has used the manual login and the login name is
  89              // unknown, so we return false.
  90              return false;
  91          }
  92      }
  93  
  94  
  95  
  96      /**
  97       * Returns the user information for 'external' users. In this case the
  98       * attributes provided by Shibboleth
  99       *
 100       * @return array $result Associative array of user data
 101       */
 102      function get_userinfo($username) {
 103      // reads user information from shibboleth attributes and return it in array()
 104          global $CFG;
 105  
 106          // Check whether we have got all the essential attributes
 107          if ( empty($_SERVER[$this->config->user_attribute]) ) {
 108              print_error( 'shib_not_all_attributes_error', 'auth_shibboleth' , '', "'".$this->config->user_attribute."' ('".$_SERVER[$this->config->user_attribute]."'), '".$this->config->field_map_firstname."' ('".$_SERVER[$this->config->field_map_firstname]."'), '".$this->config->field_map_lastname."' ('".$_SERVER[$this->config->field_map_lastname]."') and '".$this->config->field_map_email."' ('".$_SERVER[$this->config->field_map_email]."')");
 109          }
 110  
 111          $attrmap = $this->get_attributes();
 112  
 113          $result = array();
 114          $search_attribs = array();
 115  
 116          foreach ($attrmap as $key=>$value) {
 117              // Check if attribute is present
 118              if (!isset($_SERVER[$value])){
 119                  $result[$key] = '';
 120                  continue;
 121              }
 122  
 123              // Make usename lowercase
 124              if ($key == 'username'){
 125                  $result[$key] = strtolower($this->get_first_string($_SERVER[$value]));
 126              } else {
 127                  $result[$key] = $this->get_first_string($_SERVER[$value]);
 128              }
 129          }
 130  
 131           // Provide an API to modify the information to fit the Moodle internal
 132          // data representation
 133          if (
 134                $this->config->convert_data
 135                && $this->config->convert_data != ''
 136                && is_readable($this->config->convert_data)
 137              ) {
 138  
 139              // Include a custom file outside the Moodle dir to
 140              // modify the variable $moodleattributes
 141              include($this->config->convert_data);
 142          }
 143  
 144          return $result;
 145      }
 146  
 147      /**
 148       * Returns array containg attribute mappings between Moodle and Shibboleth.
 149       *
 150       * @return array
 151       */
 152      function get_attributes() {
 153          $configarray = (array) $this->config;
 154  
 155          $moodleattributes = array();
 156          $userfields = array_merge($this->userfields, $this->get_custom_user_profile_fields());
 157          foreach ($userfields as $field) {
 158              if (isset($configarray["field_map_$field"])) {
 159                  $moodleattributes[$field] = $configarray["field_map_$field"];
 160              }
 161          }
 162          $moodleattributes['username'] = $configarray["user_attribute"];
 163  
 164          return $moodleattributes;
 165      }
 166  
 167      function prevent_local_passwords() {
 168          return true;
 169      }
 170  
 171      /**
 172       * Returns true if this authentication plugin is 'internal'.
 173       *
 174       * @return bool
 175       */
 176      function is_internal() {
 177          return false;
 178      }
 179  
 180      /**
 181       * Returns true if this authentication plugin can change the user's
 182       * password.
 183       *
 184       * @return bool
 185       */
 186      function can_change_password() {
 187          return false;
 188      }
 189  
 190       /**
 191       * Hook for login page
 192       *
 193       */
 194      function loginpage_hook() {
 195          global $SESSION, $CFG;
 196  
 197          // Prevent username from being shown on login page after logout
 198          $CFG->nolastloggedin = true;
 199  
 200          return;
 201      }
 202  
 203       /**
 204       * Hook for logout page
 205       *
 206       */
 207      function logoutpage_hook() {
 208          global $SESSION, $redirect;
 209  
 210          // Only do this if logout handler is defined, and if the user is actually logged in via Shibboleth
 211          $logouthandlervalid = isset($this->config->logout_handler) && !empty($this->config->logout_handler);
 212          if (isset($SESSION->shibboleth_session_id) && $logouthandlervalid ) {
 213              // Check if there is an alternative logout return url defined
 214              if (isset($this->config->logout_return_url) && !empty($this->config->logout_return_url)) {
 215                  // Set temp_redirect to alternative return url
 216                  $temp_redirect = $this->config->logout_return_url;
 217              } else {
 218                  // Backup old redirect url
 219                  $temp_redirect = $redirect;
 220              }
 221  
 222              // Overwrite redirect in order to send user to Shibboleth logout page and let him return back
 223              $redirecturl = new moodle_url($this->config->logout_handler, array('return' => $temp_redirect));
 224              $redirect = $redirecturl->out();
 225          }
 226      }
 227  
 228  
 229  
 230      /**
 231       * Prints a form for configuring this authentication plugin.
 232       *
 233       * This function is called from admin/auth.php, and outputs a full page with
 234       * a form for configuring this plugin.
 235       *
 236       * @param array $page An object containing all the data for this page.
 237       */
 238      function config_form($config, $err, $user_fields) {
 239          include  "config.html";
 240      }
 241  
 242      /**
 243       * Processes and stores configuration data for this authentication plugin.
 244       *
 245       *
 246       * @param object $config Configuration object
 247       */
 248      function process_config($config) {
 249          global $CFG;
 250  
 251          // set to defaults if undefined
 252          if (!isset($config->auth_instructions) or empty($config->user_attribute)) {
 253              $config->auth_instructions = get_string('auth_shib_instructions', 'auth_shibboleth', $CFG->wwwroot.'/auth/shibboleth/index.php');
 254          }
 255          if (!isset ($config->user_attribute)) {
 256              $config->user_attribute = '';
 257          }
 258          if (!isset ($config->convert_data)) {
 259              $config->convert_data = '';
 260          }
 261  
 262          if (!isset($config->changepasswordurl)) {
 263              $config->changepasswordurl = '';
 264          }
 265  
 266          if (!isset($config->login_name)) {
 267              $config->login_name = 'Shibboleth Login';
 268          }
 269  
 270          // Clean idp list
 271          if (isset($config->organization_selection) && !empty($config->organization_selection) && isset($config->alt_login) && $config->alt_login == 'on') {
 272              $idp_list = get_idp_list($config->organization_selection);
 273              if (count($idp_list) < 1){
 274                  return false;
 275              }
 276              $config->organization_selection = '';
 277              foreach ($idp_list as $idp => $value){
 278                  $config->organization_selection .= $idp.', '.$value[0].', '.$value[1]."\n";
 279              }
 280          }
 281  
 282  
 283          // save settings
 284          set_config('user_attribute',    $config->user_attribute,    'auth/shibboleth');
 285  
 286          if (isset($config->organization_selection) && !empty($config->organization_selection)) {
 287              set_config('organization_selection',    $config->organization_selection,    'auth/shibboleth');
 288          }
 289          set_config('logout_handler',    $config->logout_handler,    'auth/shibboleth');
 290          set_config('logout_return_url',    $config->logout_return_url,    'auth/shibboleth');
 291          set_config('login_name',    $config->login_name,    'auth/shibboleth');
 292          set_config('convert_data',      $config->convert_data,      'auth/shibboleth');
 293          set_config('auth_instructions', $config->auth_instructions, 'auth/shibboleth');
 294          set_config('changepasswordurl', $config->changepasswordurl, 'auth/shibboleth');
 295  
 296          // Overwrite alternative login URL if integrated WAYF is used
 297          if (isset($config->alt_login) && $config->alt_login == 'on'){
 298              set_config('alt_login',    $config->alt_login,    'auth/shibboleth');
 299              set_config('alternateloginurl', $CFG->wwwroot.'/auth/shibboleth/login.php');
 300          } else {
 301              // Check if integrated WAYF was enabled and is now turned off
 302              // If it was and only then, reset the Moodle alternate URL
 303              if (isset($this->config->alt_login) and $this->config->alt_login == 'on'){
 304                  set_config('alt_login',    'off',    'auth/shibboleth');
 305                  set_config('alternateloginurl', '');
 306              }
 307              $config->alt_login = 'off';
 308          }
 309  
 310          // Check values and return false if something is wrong
 311          // Patch Anyware Technologies (14/05/07)
 312          if (($config->convert_data != '')&&(!file_exists($config->convert_data) || !is_readable($config->convert_data))){
 313              return false;
 314          }
 315  
 316          // Check if there is at least one entry in the IdP list
 317          if (isset($config->organization_selection) && empty($config->organization_selection) && isset($config->alt_login) && $config->alt_login == 'on'){
 318              return false;
 319          }
 320  
 321          return true;
 322      }
 323  
 324      /**
 325       * Cleans and returns first of potential many values (multi-valued attributes)
 326       *
 327       * @param string $string Possibly multi-valued attribute from Shibboleth
 328       */
 329      function get_first_string($string) {
 330          $list = explode( ';', $string);
 331          $clean_string = rtrim($list[0]);
 332  
 333          return $clean_string;
 334      }
 335  }
 336  
 337  
 338      /**
 339       * Sets the standard SAML domain cookie that is also used to preselect
 340       * the right entry on the local wayf
 341       *
 342       * @param IdP identifiere
 343       */
 344      function set_saml_cookie($selectedIDP) {
 345          if (isset($_COOKIE['_saml_idp']))
 346          {
 347              $IDPArray = generate_cookie_array($_COOKIE['_saml_idp']);
 348          }
 349          else
 350          {
 351              $IDPArray = array();
 352          }
 353          $IDPArray = appendCookieValue($selectedIDP, $IDPArray);
 354          setcookie ('_saml_idp', generate_cookie_value($IDPArray), time() + (100*24*3600));
 355      }
 356  
 357       /**
 358       * Prints the option elements for the select element of the drop down list
 359       *
 360       */
 361      function print_idp_list(){
 362          $config = get_config('auth/shibboleth');
 363  
 364          $IdPs = get_idp_list($config->organization_selection);
 365          if (isset($_COOKIE['_saml_idp'])){
 366              $idp_cookie = generate_cookie_array($_COOKIE['_saml_idp']);
 367              do {
 368                  $selectedIdP = array_pop($idp_cookie);
 369              } while (!isset($IdPs[$selectedIdP]) && count($idp_cookie) > 0);
 370  
 371          } else {
 372              $selectedIdP = '-';
 373          }
 374  
 375          foreach($IdPs as $IdP => $data){
 376              if ($IdP == $selectedIdP){
 377                  echo '<option value="'.$IdP.'" selected="selected">'.$data[0].'</option>';
 378              } else {
 379                  echo '<option value="'.$IdP.'">'.$data[0].'</option>';
 380              }
 381          }
 382      }
 383  
 384  
 385       /**
 386       * Generate array of IdPs from Moodle Shibboleth settings
 387       *
 388       * @param string Text containing tuble/triple of IdP entityId, name and (optionally) session initiator
 389       * @return array Identifier of IdPs and their name/session initiator
 390       */
 391  
 392      function get_idp_list($organization_selection) {
 393          $idp_list = array();
 394  
 395          $idp_raw_list = explode("\n",  $organization_selection);
 396  
 397          foreach ($idp_raw_list as $idp_line){
 398              $idp_data = explode(',', $idp_line);
 399              if (isset($idp_data[2]))
 400              {
 401                  $idp_list[trim($idp_data[0])] = array(trim($idp_data[1]),trim($idp_data[2]));
 402              }
 403              elseif(isset($idp_data[1]))
 404              {
 405                  $idp_list[trim($idp_data[0])] = array(trim($idp_data[1]));
 406              }
 407          }
 408  
 409          return $idp_list;
 410      }
 411  
 412      /**
 413       * Generates an array of IDPs using the cookie value
 414       *
 415       * @param string Value of SAML domain cookie
 416       * @return array Identifiers of IdPs
 417       */
 418      function generate_cookie_array($value) {
 419  
 420          // Decodes and splits cookie value
 421          $CookieArray = explode(' ', $value);
 422          $CookieArray = array_map('base64_decode', $CookieArray);
 423  
 424          return $CookieArray;
 425      }
 426  
 427      /**
 428       * Generate the value that is stored in the cookie using the list of IDPs
 429       *
 430       * @param array IdP identifiers
 431       * @return string SAML domain cookie value
 432       */
 433      function generate_cookie_value($CookieArray) {
 434  
 435          // Merges cookie content and encodes it
 436          $CookieArray = array_map('base64_encode', $CookieArray);
 437          $value = implode(' ', $CookieArray);
 438          return $value;
 439      }
 440  
 441      /**
 442       * Append a value to the array of IDPs
 443       *
 444       * @param string IdP identifier
 445       * @param array IdP identifiers
 446       * @return array IdP identifiers with appended IdP
 447       */
 448      function appendCookieValue($value, $CookieArray) {
 449  
 450          array_push($CookieArray, $value);
 451          $CookieArray = array_reverse($CookieArray);
 452          $CookieArray = array_unique($CookieArray);
 453          $CookieArray = array_reverse($CookieArray);
 454  
 455          return $CookieArray;
 456      }
 457  
 458  
 459  


Generated: Thu Aug 11 10:00:09 2016 Cross-referenced by PHPXref 0.7.1