[ Index ]

PHP Cross Reference of moodle-2.8

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


Generated: Fri Nov 28 20:29:05 2014 Cross-referenced by PHPXref 0.7.1