Differences Between: [Versions 310 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 /** 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/vendor/autoload.php'); 33 require_once($CFG->dirroot.'/auth/cas/CAS/vendor/apereo/phpcas/source/CAS.php'); 34 35 /** 36 * CAS authentication plugin. 37 */ 38 class auth_plugin_cas extends auth_plugin_ldap { 39 40 /** 41 * Constructor. 42 */ 43 public function __construct() { 44 $this->authtype = 'cas'; 45 $this->roleauth = 'auth_cas'; 46 $this->errorlogtag = '[AUTH CAS] '; 47 $this->init_plugin($this->authtype); 48 } 49 50 /** 51 * Old syntax of class constructor. Deprecated in PHP7. 52 * 53 * @deprecated since Moodle 3.1 54 */ 55 public function auth_plugin_cas() { 56 debugging('Use of class name as constructor is deprecated', DEBUG_DEVELOPER); 57 self::__construct(); 58 } 59 60 function prevent_local_passwords() { 61 return true; 62 } 63 64 /** 65 * Authenticates user against CAS 66 * Returns true if the username and password work and false if they are 67 * wrong or don't exist. 68 * 69 * @param string $username The username (with system magic quotes) 70 * @param string $password The password (with system magic quotes) 71 * @return bool Authentication success or failure. 72 */ 73 function user_login ($username, $password) { 74 $this->connectCAS(); 75 return phpCAS::isAuthenticated() && (trim(core_text::strtolower(phpCAS::getUser())) == $username); 76 } 77 78 /** 79 * Returns true if this authentication plugin is 'internal'. 80 * 81 * @return bool 82 */ 83 function is_internal() { 84 return false; 85 } 86 87 /** 88 * Returns true if this authentication plugin can change the user's 89 * password. 90 * 91 * @return bool 92 */ 93 function can_change_password() { 94 return false; 95 } 96 97 /** 98 * Authentication choice (CAS or other) 99 * Redirection to the CAS form or to login/index.php 100 * for other authentication 101 */ 102 function loginpage_hook() { 103 global $frm; 104 global $CFG; 105 global $SESSION, $OUTPUT, $PAGE; 106 107 $site = get_site(); 108 $CASform = get_string('CASform', 'auth_cas'); 109 $username = optional_param('username', '', PARAM_RAW); 110 $courseid = optional_param('courseid', 0, PARAM_INT); 111 112 if (!empty($username)) { 113 if (isset($SESSION->wantsurl) && (strstr($SESSION->wantsurl, 'ticket') || 114 strstr($SESSION->wantsurl, 'NOCAS'))) { 115 unset($SESSION->wantsurl); 116 } 117 return; 118 } 119 120 // Return if CAS enabled and settings not specified yet 121 if (empty($this->config->hostname)) { 122 return; 123 } 124 125 // If the multi-authentication setting is used, check for the param before connecting to CAS. 126 if ($this->config->multiauth) { 127 128 // If there is an authentication error, stay on the default authentication page. 129 if (!empty($SESSION->loginerrormsg)) { 130 return; 131 } 132 133 $authCAS = optional_param('authCAS', '', PARAM_RAW); 134 if ($authCAS != 'CAS') { 135 return; 136 } 137 138 } 139 140 // Connection to CAS server 141 $this->connectCAS(); 142 143 if (phpCAS::checkAuthentication()) { 144 $frm = new stdClass(); 145 $frm->username = phpCAS::getUser(); 146 $frm->password = 'passwdCas'; 147 $frm->logintoken = \core\session\manager::get_login_token(); 148 149 // Redirect to a course if multi-auth is activated, authCAS is set to CAS and the courseid is specified. 150 if ($this->config->multiauth && !empty($courseid)) { 151 redirect(new moodle_url('/course/view.php', array('id'=>$courseid))); 152 } 153 154 return; 155 } 156 157 if (isset($_GET['loginguest']) && ($_GET['loginguest'] == true)) { 158 $frm = new stdClass(); 159 $frm->username = 'guest'; 160 $frm->password = 'guest'; 161 $frm->logintoken = \core\session\manager::get_login_token(); 162 return; 163 } 164 165 // Force CAS authentication (if needed). 166 if (!phpCAS::isAuthenticated()) { 167 phpCAS::setLang($this->config->language); 168 phpCAS::forceAuthentication(); 169 } 170 } 171 172 173 /** 174 * Connect to the CAS (clientcas connection or proxycas connection) 175 * 176 */ 177 function connectCAS() { 178 global $CFG; 179 static $connected = false; 180 181 if (!$connected) { 182 // Form the base URL of the server with just the protocol and hostname. 183 $serverurl = new moodle_url("/"); 184 $servicebaseurl = $serverurl->get_scheme() ? $serverurl->get_scheme() . "://" : ''; 185 $servicebaseurl .= $serverurl->get_host(); 186 // Add the port if set. 187 $servicebaseurl .= $serverurl->get_port() ? ':' . $serverurl->get_port() : ''; 188 189 // Make sure phpCAS doesn't try to start a new PHP session when connecting to the CAS server. 190 if ($this->config->proxycas) { 191 phpCAS::proxy($this->config->casversion, $this->config->hostname, (int) $this->config->port, $this->config->baseuri, 192 $servicebaseurl, false); 193 } else { 194 phpCAS::client($this->config->casversion, $this->config->hostname, (int) $this->config->port, 195 $this->config->baseuri, $servicebaseurl, false); 196 } 197 // Some CAS installs require SSLv3 that should be explicitly set. 198 if (!empty($this->config->curl_ssl_version)) { 199 phpCAS::setExtraCurlOption(CURLOPT_SSLVERSION, $this->config->curl_ssl_version); 200 } 201 202 $connected = true; 203 } 204 205 // If Moodle is configured to use a proxy, phpCAS needs some curl options set. 206 if (!empty($CFG->proxyhost) && !is_proxybypass(phpCAS::getServerLoginURL())) { 207 phpCAS::setExtraCurlOption(CURLOPT_PROXY, $CFG->proxyhost); 208 if (!empty($CFG->proxyport)) { 209 phpCAS::setExtraCurlOption(CURLOPT_PROXYPORT, $CFG->proxyport); 210 } 211 if (!empty($CFG->proxytype)) { 212 // Only set CURLOPT_PROXYTYPE if it's something other than the curl-default http 213 if ($CFG->proxytype == 'SOCKS5') { 214 phpCAS::setExtraCurlOption(CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5); 215 } 216 } 217 if (!empty($CFG->proxyuser) and !empty($CFG->proxypassword)) { 218 phpCAS::setExtraCurlOption(CURLOPT_PROXYUSERPWD, $CFG->proxyuser.':'.$CFG->proxypassword); 219 if (defined('CURLOPT_PROXYAUTH')) { 220 // any proxy authentication if PHP 5.1 221 phpCAS::setExtraCurlOption(CURLOPT_PROXYAUTH, CURLAUTH_BASIC | CURLAUTH_NTLM); 222 } 223 } 224 } 225 226 if ($this->config->certificate_check && $this->config->certificate_path){ 227 phpCAS::setCasServerCACert($this->config->certificate_path); 228 } else { 229 // Don't try to validate the server SSL credentials 230 phpCAS::setNoCasServerValidation(); 231 } 232 } 233 234 /** 235 * Returns the URL for changing the user's pw, or empty if the default can 236 * be used. 237 * 238 * @return moodle_url 239 */ 240 function change_password_url() { 241 return null; 242 } 243 244 /** 245 * Returns true if user should be coursecreator. 246 * 247 * @param mixed $username username (without system magic quotes) 248 * @return boolean result 249 */ 250 function iscreator($username) { 251 if (empty($this->config->host_url) or (empty($this->config->attrcreators) && empty($this->config->groupecreators)) or empty($this->config->memberattribute)) { 252 return false; 253 } 254 255 $extusername = core_text::convert($username, 'utf-8', $this->config->ldapencoding); 256 257 // Test for group creator 258 if (!empty($this->config->groupecreators)) { 259 $ldapconnection = $this->ldap_connect(); 260 if ($this->config->memberattribute_isdn) { 261 if(!($userid = $this->ldap_find_userdn($ldapconnection, $extusername))) { 262 return false; 263 } 264 } else { 265 $userid = $extusername; 266 } 267 268 $group_dns = explode(';', $this->config->groupecreators); 269 if (ldap_isgroupmember($ldapconnection, $userid, $group_dns, $this->config->memberattribute)) { 270 return true; 271 } 272 } 273 274 // Build filter for attrcreator 275 if (!empty($this->config->attrcreators)) { 276 $attrs = explode(';', $this->config->attrcreators); 277 $filter = '(& ('.$this->config->user_attribute."=$username)(|"; 278 foreach ($attrs as $attr){ 279 if(strpos($attr, '=')) { 280 $filter .= "($attr)"; 281 } else { 282 $filter .= '('.$this->config->memberattribute."=$attr)"; 283 } 284 } 285 $filter .= '))'; 286 287 // Search 288 $result = $this->ldap_get_userlist($filter); 289 if (count($result) != 0) { 290 return true; 291 } 292 } 293 294 return false; 295 } 296 297 /** 298 * Reads user information from LDAP and returns it as array() 299 * 300 * If no LDAP servers are configured, user information has to be 301 * provided via other methods (CSV file, manually, etc.). Return 302 * an empty array so existing user info is not lost. Otherwise, 303 * calls parent class method to get user info. 304 * 305 * @param string $username username 306 * @return mixed array with no magic quotes or false on error 307 */ 308 function get_userinfo($username) { 309 if (empty($this->config->host_url)) { 310 return array(); 311 } 312 return parent::get_userinfo($username); 313 } 314 315 /** 316 * Syncronizes users from LDAP server to moodle user table. 317 * 318 * If no LDAP servers are configured, simply return. Otherwise, 319 * call parent class method to do the work. 320 * 321 * @param bool $do_updates will do pull in data updates from LDAP if relevant 322 * @return nothing 323 */ 324 function sync_users($do_updates=true) { 325 if (empty($this->config->host_url)) { 326 error_log('[AUTH CAS] '.get_string('noldapserver', 'auth_cas')); 327 return; 328 } 329 parent::sync_users($do_updates); 330 } 331 332 /** 333 * Hook for logout page 334 */ 335 function logoutpage_hook() { 336 global $USER, $redirect; 337 338 // Only do this if the user is actually logged in via CAS 339 if ($USER->auth === $this->authtype) { 340 // Check if there is an alternative logout return url defined 341 if (isset($this->config->logout_return_url) && !empty($this->config->logout_return_url)) { 342 // Set redirect to alternative return url 343 $redirect = $this->config->logout_return_url; 344 } 345 } 346 } 347 348 /** 349 * Post logout hook. 350 * 351 * Note: this method replace the prelogout_hook method to avoid redirect to CAS logout 352 * before the event userlogout being triggered. 353 * 354 * @param stdClass $user clone of USER object object before the user session was terminated 355 */ 356 public function postlogout_hook($user) { 357 global $CFG; 358 // Only redirect to CAS logout if the user is logged as a CAS user. 359 if (!empty($this->config->logoutcas) && $user->auth == $this->authtype) { 360 $backurl = !empty($this->config->logout_return_url) ? $this->config->logout_return_url : $CFG->wwwroot; 361 $this->connectCAS(); 362 phpCAS::logoutWithRedirectService($backurl); 363 } 364 } 365 366 /** 367 * Return a list of identity providers to display on the login page. 368 * 369 * @param string|moodle_url $wantsurl The requested URL. 370 * @return array List of arrays with keys url, iconurl and name. 371 */ 372 public function loginpage_idp_list($wantsurl) { 373 if (empty($this->config->hostname)) { 374 // CAS is not configured. 375 return []; 376 } 377 378 if ($this->config->auth_logo) { 379 $iconurl = moodle_url::make_pluginfile_url( 380 context_system::instance()->id, 381 'auth_cas', 382 'logo', 383 null, 384 null, 385 $this->config->auth_logo); 386 } else { 387 $iconurl = null; 388 } 389 390 return [ 391 [ 392 'url' => new moodle_url(get_login_url(), [ 393 'authCAS' => 'CAS', 394 ]), 395 'iconurl' => $iconurl, 396 'name' => format_string($this->config->auth_name), 397 ], 398 ]; 399 } 400 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body