Differences Between: [Versions 310 and 311] [Versions 310 and 400] [Versions 310 and 401] [Versions 310 and 402] [Versions 310 and 403] [Versions 39 and 310]
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 != 'CAS') { 134 return; 135 } 136 137 } 138 139 // Connection to CAS server 140 $this->connectCAS(); 141 142 if (phpCAS::checkAuthentication()) { 143 $frm = new stdClass(); 144 $frm->username = phpCAS::getUser(); 145 $frm->password = 'passwdCas'; 146 $frm->logintoken = \core\session\manager::get_login_token(); 147 148 // Redirect to a course if multi-auth is activated, authCAS is set to CAS and the courseid is specified. 149 if ($this->config->multiauth && !empty($courseid)) { 150 redirect(new moodle_url('/course/view.php', array('id'=>$courseid))); 151 } 152 153 return; 154 } 155 156 if (isset($_GET['loginguest']) && ($_GET['loginguest'] == true)) { 157 $frm = new stdClass(); 158 $frm->username = 'guest'; 159 $frm->password = 'guest'; 160 $frm->logintoken = \core\session\manager::get_login_token(); 161 return; 162 } 163 164 // Force CAS authentication (if needed). 165 if (!phpCAS::isAuthenticated()) { 166 phpCAS::setLang($this->config->language); 167 phpCAS::forceAuthentication(); 168 } 169 } 170 171 172 /** 173 * Connect to the CAS (clientcas connection or proxycas connection) 174 * 175 */ 176 function connectCAS() { 177 global $CFG; 178 static $connected = false; 179 180 if (!$connected) { 181 // Make sure phpCAS doesn't try to start a new PHP session when connecting to the CAS server. 182 if ($this->config->proxycas) { 183 phpCAS::proxy($this->config->casversion, $this->config->hostname, (int) $this->config->port, $this->config->baseuri, false); 184 } else { 185 phpCAS::client($this->config->casversion, $this->config->hostname, (int) $this->config->port, $this->config->baseuri, false); 186 } 187 // Some CAS installs require SSLv3 that should be explicitly set. 188 if (!empty($this->config->curl_ssl_version)) { 189 phpCAS::setExtraCurlOption(CURLOPT_SSLVERSION, $this->config->curl_ssl_version); 190 } 191 192 $connected = true; 193 } 194 195 // If Moodle is configured to use a proxy, phpCAS needs some curl options set. 196 if (!empty($CFG->proxyhost) && !is_proxybypass(phpCAS::getServerLoginURL())) { 197 phpCAS::setExtraCurlOption(CURLOPT_PROXY, $CFG->proxyhost); 198 if (!empty($CFG->proxyport)) { 199 phpCAS::setExtraCurlOption(CURLOPT_PROXYPORT, $CFG->proxyport); 200 } 201 if (!empty($CFG->proxytype)) { 202 // Only set CURLOPT_PROXYTYPE if it's something other than the curl-default http 203 if ($CFG->proxytype == 'SOCKS5') { 204 phpCAS::setExtraCurlOption(CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5); 205 } 206 } 207 if (!empty($CFG->proxyuser) and !empty($CFG->proxypassword)) { 208 phpCAS::setExtraCurlOption(CURLOPT_PROXYUSERPWD, $CFG->proxyuser.':'.$CFG->proxypassword); 209 if (defined('CURLOPT_PROXYAUTH')) { 210 // any proxy authentication if PHP 5.1 211 phpCAS::setExtraCurlOption(CURLOPT_PROXYAUTH, CURLAUTH_BASIC | CURLAUTH_NTLM); 212 } 213 } 214 } 215 216 if ($this->config->certificate_check && $this->config->certificate_path){ 217 phpCAS::setCasServerCACert($this->config->certificate_path); 218 } else { 219 // Don't try to validate the server SSL credentials 220 phpCAS::setNoCasServerValidation(); 221 } 222 } 223 224 /** 225 * Returns the URL for changing the user's pw, or empty if the default can 226 * be used. 227 * 228 * @return moodle_url 229 */ 230 function change_password_url() { 231 return null; 232 } 233 234 /** 235 * Returns true if user should be coursecreator. 236 * 237 * @param mixed $username username (without system magic quotes) 238 * @return boolean result 239 */ 240 function iscreator($username) { 241 if (empty($this->config->host_url) or (empty($this->config->attrcreators) && empty($this->config->groupecreators)) or empty($this->config->memberattribute)) { 242 return false; 243 } 244 245 $extusername = core_text::convert($username, 'utf-8', $this->config->ldapencoding); 246 247 // Test for group creator 248 if (!empty($this->config->groupecreators)) { 249 $ldapconnection = $this->ldap_connect(); 250 if ($this->config->memberattribute_isdn) { 251 if(!($userid = $this->ldap_find_userdn($ldapconnection, $extusername))) { 252 return false; 253 } 254 } else { 255 $userid = $extusername; 256 } 257 258 $group_dns = explode(';', $this->config->groupecreators); 259 if (ldap_isgroupmember($ldapconnection, $userid, $group_dns, $this->config->memberattribute)) { 260 return true; 261 } 262 } 263 264 // Build filter for attrcreator 265 if (!empty($this->config->attrcreators)) { 266 $attrs = explode(';', $this->config->attrcreators); 267 $filter = '(& ('.$this->config->user_attribute."=$username)(|"; 268 foreach ($attrs as $attr){ 269 if(strpos($attr, '=')) { 270 $filter .= "($attr)"; 271 } else { 272 $filter .= '('.$this->config->memberattribute."=$attr)"; 273 } 274 } 275 $filter .= '))'; 276 277 // Search 278 $result = $this->ldap_get_userlist($filter); 279 if (count($result) != 0) { 280 return true; 281 } 282 } 283 284 return false; 285 } 286 287 /** 288 * Reads user information from LDAP and returns it as array() 289 * 290 * If no LDAP servers are configured, user information has to be 291 * provided via other methods (CSV file, manually, etc.). Return 292 * an empty array so existing user info is not lost. Otherwise, 293 * calls parent class method to get user info. 294 * 295 * @param string $username username 296 * @return mixed array with no magic quotes or false on error 297 */ 298 function get_userinfo($username) { 299 if (empty($this->config->host_url)) { 300 return array(); 301 } 302 return parent::get_userinfo($username); 303 } 304 305 /** 306 * Syncronizes users from LDAP server to moodle user table. 307 * 308 * If no LDAP servers are configured, simply return. Otherwise, 309 * call parent class method to do the work. 310 * 311 * @param bool $do_updates will do pull in data updates from LDAP if relevant 312 * @return nothing 313 */ 314 function sync_users($do_updates=true) { 315 if (empty($this->config->host_url)) { 316 error_log('[AUTH CAS] '.get_string('noldapserver', 'auth_cas')); 317 return; 318 } 319 parent::sync_users($do_updates); 320 } 321 322 /** 323 * Hook for logout page 324 */ 325 function logoutpage_hook() { 326 global $USER, $redirect; 327 328 // Only do this if the user is actually logged in via CAS 329 if ($USER->auth === $this->authtype) { 330 // Check if there is an alternative logout return url defined 331 if (isset($this->config->logout_return_url) && !empty($this->config->logout_return_url)) { 332 // Set redirect to alternative return url 333 $redirect = $this->config->logout_return_url; 334 } 335 } 336 } 337 338 /** 339 * Post logout hook. 340 * 341 * Note: this method replace the prelogout_hook method to avoid redirect to CAS logout 342 * before the event userlogout being triggered. 343 * 344 * @param stdClass $user clone of USER object object before the user session was terminated 345 */ 346 public function postlogout_hook($user) { 347 global $CFG; 348 // Only redirect to CAS logout if the user is logged as a CAS user. 349 if (!empty($this->config->logoutcas) && $user->auth == $this->authtype) { 350 $backurl = !empty($this->config->logout_return_url) ? $this->config->logout_return_url : $CFG->wwwroot; 351 $this->connectCAS(); 352 phpCAS::logoutWithRedirectService($backurl); 353 } 354 } 355 356 /** 357 * Return a list of identity providers to display on the login page. 358 * 359 * @param string|moodle_url $wantsurl The requested URL. 360 * @return array List of arrays with keys url, iconurl and name. 361 */ 362 public function loginpage_idp_list($wantsurl) { 363 if (empty($this->config->hostname)) { 364 // CAS is not configured. 365 return []; 366 } 367 368 if ($this->config->auth_logo) { 369 $iconurl = moodle_url::make_pluginfile_url( 370 context_system::instance()->id, 371 'auth_cas', 372 'logo', 373 null, 374 null, 375 $this->config->auth_logo); 376 } else { 377 $iconurl = null; 378 } 379 380 return [ 381 [ 382 'url' => new moodle_url(get_login_url(), [ 383 'authCAS' => 'CAS', 384 ]), 385 'iconurl' => $iconurl, 386 'name' => format_string($this->config->auth_name), 387 ], 388 ]; 389 } 390 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body