[ Index ]

PHP Cross Reference of Unnamed Project

title

Body

[close]

/auth/cas/ -> 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: CAS Authentication
  19   *
  20   * Authentication using CAS (Central Authentication Server).
  21   *
  22   * @author Martin Dougiamas
  23   * @author Jerome GUTIERREZ
  24   * @author IƱaki Arenaza
  25   * @license http://www.gnu.org/copyleft/gpl.html GNU Public License
  26   * @package auth_cas
  27   */
  28  
  29  defined('MOODLE_INTERNAL') || die();
  30  
  31  require_once($CFG->dirroot.'/auth/ldap/auth.php');
  32  require_once($CFG->dirroot.'/auth/cas/CAS/CAS.php');
  33  
  34  /**
  35   * CAS authentication plugin.
  36   */
  37  class auth_plugin_cas extends auth_plugin_ldap {
  38  
  39      /**
  40       * Constructor.
  41       */
  42      public function __construct() {
  43          $this->authtype = 'cas';
  44          $this->roleauth = 'auth_cas';
  45          $this->errorlogtag = '[AUTH CAS] ';
  46          $this->init_plugin($this->authtype);
  47      }
  48  
  49      /**
  50       * Old syntax of class constructor. Deprecated in PHP7.
  51       *
  52       * @deprecated since Moodle 3.1
  53       */
  54      public function auth_plugin_cas() {
  55          debugging('Use of class name as constructor is deprecated', DEBUG_DEVELOPER);
  56          self::__construct();
  57      }
  58  
  59      function prevent_local_passwords() {
  60          return true;
  61      }
  62  
  63      /**
  64       * Authenticates user against CAS
  65       * Returns true if the username and password work and false if they are
  66       * wrong or don't exist.
  67       *
  68       * @param string $username The username (with system magic quotes)
  69       * @param string $password The password (with system magic quotes)
  70       * @return bool Authentication success or failure.
  71       */
  72      function user_login ($username, $password) {
  73          $this->connectCAS();
  74          return phpCAS::isAuthenticated() && (trim(core_text::strtolower(phpCAS::getUser())) == $username);
  75      }
  76  
  77      /**
  78       * Returns true if this authentication plugin is 'internal'.
  79       *
  80       * @return bool
  81       */
  82      function is_internal() {
  83          return false;
  84      }
  85  
  86      /**
  87       * Returns true if this authentication plugin can change the user's
  88       * password.
  89       *
  90       * @return bool
  91       */
  92      function can_change_password() {
  93          return false;
  94      }
  95  
  96      /**
  97       * Authentication choice (CAS or other)
  98       * Redirection to the CAS form or to login/index.php
  99       * for other authentication
 100       */
 101      function loginpage_hook() {
 102          global $frm;
 103          global $CFG;
 104          global $SESSION, $OUTPUT, $PAGE;
 105  
 106          $site = get_site();
 107          $CASform = get_string('CASform', 'auth_cas');
 108          $username = optional_param('username', '', PARAM_RAW);
 109          $courseid = optional_param('courseid', 0, PARAM_INT);
 110  
 111          if (!empty($username)) {
 112              if (isset($SESSION->wantsurl) && (strstr($SESSION->wantsurl, 'ticket') ||
 113                                                strstr($SESSION->wantsurl, 'NOCAS'))) {
 114                  unset($SESSION->wantsurl);
 115              }
 116              return;
 117          }
 118  
 119          // Return if CAS enabled and settings not specified yet
 120          if (empty($this->config->hostname)) {
 121              return;
 122          }
 123  
 124          // If the multi-authentication setting is used, check for the param before connecting to CAS.
 125          if ($this->config->multiauth) {
 126  
 127              // If there is an authentication error, stay on the default authentication page.
 128              if (!empty($SESSION->loginerrormsg)) {
 129                  return;
 130              }
 131  
 132              $authCAS = optional_param('authCAS', '', PARAM_RAW);
 133              if ($authCAS == 'NOCAS') {
 134                  return;
 135              }
 136              // Show authentication form for multi-authentication.
 137              // Test pgtIou parameter for proxy mode (https connection in background from CAS server to the php server).
 138              if ($authCAS != 'CAS' && !isset($_GET['pgtIou'])) {
 139                  $PAGE->set_url('/login/index.php');
 140                  $PAGE->navbar->add($CASform);
 141                  $PAGE->set_title("$site->fullname: $CASform");
 142                  $PAGE->set_heading($site->fullname);
 143                  echo $OUTPUT->header();
 144                  include($CFG->dirroot.'/auth/cas/cas_form.html');
 145                  echo $OUTPUT->footer();
 146                  exit();
 147              }
 148          }
 149  
 150          // Connection to CAS server
 151          $this->connectCAS();
 152  
 153          if (phpCAS::checkAuthentication()) {
 154              $frm = new stdClass();
 155              $frm->username = phpCAS::getUser();
 156              $frm->password = 'passwdCas';
 157  
 158              // Redirect to a course if multi-auth is activated, authCAS is set to CAS and the courseid is specified.
 159              if ($this->config->multiauth && !empty($courseid)) {
 160                  redirect(new moodle_url('/course/view.php', array('id'=>$courseid)));
 161              }
 162  
 163              return;
 164          }
 165  
 166          if (isset($_GET['loginguest']) && ($_GET['loginguest'] == true)) {
 167              $frm = new stdClass();
 168              $frm->username = 'guest';
 169              $frm->password = 'guest';
 170              return;
 171          }
 172  
 173          // Force CAS authentication (if needed).
 174          if (!phpCAS::isAuthenticated()) {
 175              phpCAS::setLang($this->config->language);
 176              phpCAS::forceAuthentication();
 177          }
 178      }
 179  
 180  
 181      /**
 182       * Connect to the CAS (clientcas connection or proxycas connection)
 183       *
 184       */
 185      function connectCAS() {
 186          global $CFG;
 187          static $connected = false;
 188  
 189          if (!$connected) {
 190              // Make sure phpCAS doesn't try to start a new PHP session when connecting to the CAS server.
 191              if ($this->config->proxycas) {
 192                  phpCAS::proxy($this->config->casversion, $this->config->hostname, (int) $this->config->port, $this->config->baseuri, false);
 193              } else {
 194                  phpCAS::client($this->config->casversion, $this->config->hostname, (int) $this->config->port, $this->config->baseuri, false);
 195              }
 196              // Some CAS installs require SSLv3 that should be explicitly set.
 197              if (!empty($this->config->curl_ssl_version)) {
 198                  phpCAS::setExtraCurlOption(CURLOPT_SSLVERSION, $this->config->curl_ssl_version);
 199              }
 200  
 201              $connected = true;
 202          }
 203  
 204          // If Moodle is configured to use a proxy, phpCAS needs some curl options set.
 205          if (!empty($CFG->proxyhost) && !is_proxybypass(phpCAS::getServerLoginURL())) {
 206              phpCAS::setExtraCurlOption(CURLOPT_PROXY, $CFG->proxyhost);
 207              if (!empty($CFG->proxyport)) {
 208                  phpCAS::setExtraCurlOption(CURLOPT_PROXYPORT, $CFG->proxyport);
 209              }
 210              if (!empty($CFG->proxytype)) {
 211                  // Only set CURLOPT_PROXYTYPE if it's something other than the curl-default http
 212                  if ($CFG->proxytype == 'SOCKS5') {
 213                      phpCAS::setExtraCurlOption(CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5);
 214                  }
 215              }
 216              if (!empty($CFG->proxyuser) and !empty($CFG->proxypassword)) {
 217                  phpCAS::setExtraCurlOption(CURLOPT_PROXYUSERPWD, $CFG->proxyuser.':'.$CFG->proxypassword);
 218                  if (defined('CURLOPT_PROXYAUTH')) {
 219                      // any proxy authentication if PHP 5.1
 220                      phpCAS::setExtraCurlOption(CURLOPT_PROXYAUTH, CURLAUTH_BASIC | CURLAUTH_NTLM);
 221                  }
 222              }
 223          }
 224  
 225          if ($this->config->certificate_check && $this->config->certificate_path){
 226              phpCAS::setCasServerCACert($this->config->certificate_path);
 227          } else {
 228              // Don't try to validate the server SSL credentials
 229              phpCAS::setNoCasServerValidation();
 230          }
 231      }
 232  
 233      /**
 234       * Prints a form for configuring this authentication plugin.
 235       *
 236       * This function is called from admin/auth.php, and outputs a full page with
 237       * a form for configuring this plugin.
 238       *
 239       * @param array $page An object containing all the data for this page.
 240       */
 241      function config_form($config, $err, $user_fields) {
 242          global $CFG, $OUTPUT;
 243  
 244          if (!function_exists('ldap_connect')) { // Is php-ldap really there?
 245              echo $OUTPUT->notification(get_string('auth_ldap_noextension', 'auth_ldap'));
 246  
 247              // Don't return here, like we do in auth/ldap. We cas use CAS without LDAP.
 248              // So just warn the user (done above) and define the LDAP constants we use
 249              // in config.html, to silence the warnings.
 250              if (!defined('LDAP_DEREF_NEVER')) {
 251                  define ('LDAP_DEREF_NEVER', 0);
 252              }
 253              if (!defined('LDAP_DEREF_ALWAYS')) {
 254                  define ('LDAP_DEREF_ALWAYS', 3);
 255              }
 256          }
 257  
 258          include($CFG->dirroot.'/auth/cas/config.html');
 259      }
 260  
 261      /**
 262       * A chance to validate form data, and last chance to
 263       * do stuff before it is inserted in config_plugin
 264       * @param object object with submitted configuration settings (without system magic quotes)
 265       * @param array $err array of error messages
 266       */
 267      function validate_form($form, &$err) {
 268          $certificate_path = trim($form->certificate_path);
 269          if ($form->certificate_check && empty($certificate_path)) {
 270              $err['certificate_path'] = get_string('auth_cas_certificate_path_empty', 'auth_cas');
 271          }
 272      }
 273  
 274      /**
 275       * Returns the URL for changing the user's pw, or empty if the default can
 276       * be used.
 277       *
 278       * @return moodle_url
 279       */
 280      function change_password_url() {
 281          return null;
 282      }
 283  
 284      /**
 285       * Processes and stores configuration data for this authentication plugin.
 286       */
 287      function process_config($config) {
 288  
 289          // CAS settings
 290          if (!isset($config->hostname)) {
 291              $config->hostname = '';
 292          }
 293          if (!isset($config->port)) {
 294              $config->port = '';
 295          }
 296          if (!isset($config->casversion)) {
 297              $config->casversion = '';
 298          }
 299          if (!isset($config->baseuri)) {
 300              $config->baseuri = '';
 301          }
 302          if (!isset($config->language)) {
 303              $config->language = '';
 304          }
 305          if (!isset($config->proxycas)) {
 306              $config->proxycas = '';
 307          }
 308          if (!isset($config->logoutcas)) {
 309              $config->logoutcas = '';
 310          }
 311          if (!isset($config->multiauth)) {
 312              $config->multiauth = '';
 313          }
 314          if (!isset($config->certificate_check)) {
 315              $config->certificate_check = '';
 316          }
 317          if (!isset($config->certificate_path)) {
 318              $config->certificate_path = '';
 319          }
 320          if (!isset($config->curl_ssl_version)) {
 321              $config->curl_ssl_version = '';
 322          }
 323          if (!isset($config->logout_return_url)) {
 324              $config->logout_return_url = '';
 325          }
 326  
 327          // LDAP settings
 328          if (!isset($config->host_url)) {
 329              $config->host_url = '';
 330          }
 331          if (!isset($config->start_tls)) {
 332               $config->start_tls = false;
 333          }
 334          if (empty($config->ldapencoding)) {
 335              $config->ldapencoding = 'utf-8';
 336          }
 337          if (!isset($config->pagesize)) {
 338              $config->pagesize = LDAP_DEFAULT_PAGESIZE;
 339          }
 340          if (!isset($config->contexts)) {
 341              $config->contexts = '';
 342          }
 343          if (!isset($config->user_type)) {
 344              $config->user_type = 'default';
 345          }
 346          if (!isset($config->user_attribute)) {
 347              $config->user_attribute = '';
 348          }
 349          if (!isset($config->search_sub)) {
 350              $config->search_sub = '';
 351          }
 352          if (!isset($config->opt_deref)) {
 353              $config->opt_deref = LDAP_DEREF_NEVER;
 354          }
 355          if (!isset($config->bind_dn)) {
 356              $config->bind_dn = '';
 357          }
 358          if (!isset($config->bind_pw)) {
 359              $config->bind_pw = '';
 360          }
 361          if (!isset($config->ldap_version)) {
 362              $config->ldap_version = '3';
 363          }
 364          if (!isset($config->objectclass)) {
 365              $config->objectclass = '';
 366          }
 367          if (!isset($config->memberattribute)) {
 368              $config->memberattribute = '';
 369          }
 370  
 371          if (!isset($config->memberattribute_isdn)) {
 372              $config->memberattribute_isdn = '';
 373          }
 374          if (!isset($config->attrcreators)) {
 375              $config->attrcreators = '';
 376          }
 377          if (!isset($config->groupecreators)) {
 378              $config->groupecreators = '';
 379          }
 380          if (!isset($config->removeuser)) {
 381              $config->removeuser = AUTH_REMOVEUSER_KEEP;
 382          }
 383  
 384          // save CAS settings
 385          set_config('hostname', trim($config->hostname), $this->pluginconfig);
 386          set_config('port', trim($config->port), $this->pluginconfig);
 387          set_config('casversion', $config->casversion, $this->pluginconfig);
 388          set_config('baseuri', trim($config->baseuri), $this->pluginconfig);
 389          set_config('language', $config->language, $this->pluginconfig);
 390          set_config('proxycas', $config->proxycas, $this->pluginconfig);
 391          set_config('logoutcas', $config->logoutcas, $this->pluginconfig);
 392          set_config('multiauth', $config->multiauth, $this->pluginconfig);
 393          set_config('certificate_check', $config->certificate_check, $this->pluginconfig);
 394          set_config('certificate_path', $config->certificate_path, $this->pluginconfig);
 395          set_config('curl_ssl_version', $config->curl_ssl_version, $this->pluginconfig);
 396          set_config('logout_return_url', $config->logout_return_url, $this->pluginconfig);
 397  
 398          // save LDAP settings
 399          set_config('host_url', trim($config->host_url), $this->pluginconfig);
 400          set_config('start_tls', $config->start_tls, $this->pluginconfig);
 401          set_config('ldapencoding', trim($config->ldapencoding), $this->pluginconfig);
 402          set_config('pagesize', (int)trim($config->pagesize), $this->pluginconfig);
 403          set_config('contexts', trim($config->contexts), $this->pluginconfig);
 404          set_config('user_type', core_text::strtolower(trim($config->user_type)), $this->pluginconfig);
 405          set_config('user_attribute', core_text::strtolower(trim($config->user_attribute)), $this->pluginconfig);
 406          set_config('search_sub', $config->search_sub, $this->pluginconfig);
 407          set_config('opt_deref', $config->opt_deref, $this->pluginconfig);
 408          set_config('bind_dn', trim($config->bind_dn), $this->pluginconfig);
 409          set_config('bind_pw', $config->bind_pw, $this->pluginconfig);
 410          set_config('ldap_version', $config->ldap_version, $this->pluginconfig);
 411          set_config('objectclass', trim($config->objectclass), $this->pluginconfig);
 412          set_config('memberattribute', core_text::strtolower(trim($config->memberattribute)), $this->pluginconfig);
 413          set_config('memberattribute_isdn', $config->memberattribute_isdn, $this->pluginconfig);
 414          set_config('attrcreators', trim($config->attrcreators), $this->pluginconfig);
 415          set_config('groupecreators', trim($config->groupecreators), $this->pluginconfig);
 416          set_config('removeuser', $config->removeuser, $this->pluginconfig);
 417  
 418          return true;
 419      }
 420  
 421      /**
 422       * Returns true if user should be coursecreator.
 423       *
 424       * @param mixed $username    username (without system magic quotes)
 425       * @return boolean result
 426       */
 427      function iscreator($username) {
 428          if (empty($this->config->host_url) or (empty($this->config->attrcreators) && empty($this->config->groupecreators)) or empty($this->config->memberattribute)) {
 429              return false;
 430          }
 431  
 432          $extusername = core_text::convert($username, 'utf-8', $this->config->ldapencoding);
 433  
 434          // Test for group creator
 435          if (!empty($this->config->groupecreators)) {
 436              $ldapconnection = $this->ldap_connect();
 437              if ($this->config->memberattribute_isdn) {
 438                  if(!($userid = $this->ldap_find_userdn($ldapconnection, $extusername))) {
 439                      return false;
 440                  }
 441              } else {
 442                  $userid = $extusername;
 443              }
 444  
 445              $group_dns = explode(';', $this->config->groupecreators);
 446              if (ldap_isgroupmember($ldapconnection, $userid, $group_dns, $this->config->memberattribute)) {
 447                  return true;
 448              }
 449          }
 450  
 451          // Build filter for attrcreator
 452          if (!empty($this->config->attrcreators)) {
 453              $attrs = explode(';', $this->config->attrcreators);
 454              $filter = '(& ('.$this->config->user_attribute."=$username)(|";
 455              foreach ($attrs as $attr){
 456                  if(strpos($attr, '=')) {
 457                      $filter .= "($attr)";
 458                  } else {
 459                      $filter .= '('.$this->config->memberattribute."=$attr)";
 460                  }
 461              }
 462              $filter .= '))';
 463  
 464              // Search
 465              $result = $this->ldap_get_userlist($filter);
 466              if (count($result) != 0) {
 467                  return true;
 468              }
 469          }
 470  
 471          return false;
 472      }
 473  
 474      /**
 475       * Reads user information from LDAP and returns it as array()
 476       *
 477       * If no LDAP servers are configured, user information has to be
 478       * provided via other methods (CSV file, manually, etc.). Return
 479       * an empty array so existing user info is not lost. Otherwise,
 480       * calls parent class method to get user info.
 481       *
 482       * @param string $username username
 483       * @return mixed array with no magic quotes or false on error
 484       */
 485      function get_userinfo($username) {
 486          if (empty($this->config->host_url)) {
 487              return array();
 488          }
 489          return parent::get_userinfo($username);
 490      }
 491  
 492      /**
 493       * Syncronizes users from LDAP server to moodle user table.
 494       *
 495       * If no LDAP servers are configured, simply return. Otherwise,
 496       * call parent class method to do the work.
 497       *
 498       * @param bool $do_updates will do pull in data updates from LDAP if relevant
 499       * @return nothing
 500       */
 501      function sync_users($do_updates=true) {
 502          if (empty($this->config->host_url)) {
 503              error_log('[AUTH CAS] '.get_string('noldapserver', 'auth_cas'));
 504              return;
 505          }
 506          parent::sync_users($do_updates);
 507      }
 508  
 509      /**
 510      * Hook for logout page
 511      */
 512      function logoutpage_hook() {
 513          global $USER, $redirect;
 514  
 515          // Only do this if the user is actually logged in via CAS
 516          if ($USER->auth === $this->authtype) {
 517              // Check if there is an alternative logout return url defined
 518              if (isset($this->config->logout_return_url) && !empty($this->config->logout_return_url)) {
 519                  // Set redirect to alternative return url
 520                  $redirect = $this->config->logout_return_url;
 521              }
 522          }
 523      }
 524  
 525      /**
 526       * Post logout hook.
 527       *
 528       * Note: this method replace the prelogout_hook method to avoid redirect to CAS logout
 529       * before the event userlogout being triggered.
 530       *
 531       * @param stdClass $user clone of USER object object before the user session was terminated
 532       */
 533      public function postlogout_hook($user) {
 534          global $CFG;
 535          // Only redirect to CAS logout if the user is logged as a CAS user.
 536          if (!empty($this->config->logoutcas) && $user->auth == $this->authtype) {
 537              $backurl = !empty($this->config->logout_return_url) ? $this->config->logout_return_url : $CFG->wwwroot;
 538              $this->connectCAS();
 539              phpCAS::logoutWithRedirectService($backurl);
 540          }
 541      }
 542  }


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