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