Differences Between: [Versions 310 and 403] [Versions 311 and 403] [Versions 39 and 403] [Versions 400 and 403] [Versions 401 and 403] [Versions 402 and 403]
1 <?php 2 3 // This file is part of Moodle - http://moodle.org/ 4 // 5 // Moodle is free software: you can redistribute it and/or modify 6 // it under the terms of the GNU General Public License as published by 7 // the Free Software Foundation, either version 3 of the License, or 8 // (at your option) any later version. 9 // 10 // Moodle is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU General Public License for more details. 14 // 15 // You should have received a copy of the GNU General Public License 16 // along with Moodle. If not, see <http://www.gnu.org/licenses/>. 17 18 /** 19 * Main login page. 20 * 21 * @package core 22 * @subpackage auth 23 * @copyright 1999 onwards Martin Dougiamas http://dougiamas.com 24 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 25 */ 26 27 require('../config.php'); 28 require_once ('lib.php'); 29 30 redirect_if_major_upgrade_required(); 31 32 $testsession = optional_param('testsession', 0, PARAM_INT); // test session works properly 33 $anchor = optional_param('anchor', '', PARAM_RAW); // Used to restore hash anchor to wantsurl. 34 35 $resendconfirmemail = optional_param('resendconfirmemail', false, PARAM_BOOL); 36 37 // It might be safe to do this for non-Behat sites, or there might 38 // be a security risk. For now we only allow it on Behat sites. 39 // If you wants to do the analysis, you may be able to remove the 40 // if (BEHAT_SITE_RUNNING). 41 if (defined('BEHAT_SITE_RUNNING') && BEHAT_SITE_RUNNING) { 42 $wantsurl = optional_param('wantsurl', '', PARAM_LOCALURL); // Overrides $SESSION->wantsurl if given. 43 if ($wantsurl !== '') { 44 $SESSION->wantsurl = (new moodle_url($wantsurl))->out(false); 45 } 46 } 47 48 $context = context_system::instance(); 49 $PAGE->set_url("$CFG->wwwroot/login/index.php"); 50 $PAGE->set_context($context); 51 $PAGE->set_pagelayout('login'); 52 53 /// Initialize variables 54 $errormsg = ''; 55 $infomsg = ''; 56 $errorcode = 0; 57 58 // login page requested session test 59 if ($testsession) { 60 if ($testsession == $USER->id) { 61 if (isset($SESSION->wantsurl)) { 62 $urltogo = $SESSION->wantsurl; 63 } else { 64 $urltogo = $CFG->wwwroot.'/'; 65 } 66 unset($SESSION->wantsurl); 67 redirect($urltogo); 68 } else { 69 // TODO: try to find out what is the exact reason why sessions do not work 70 $errormsg = get_string("cookiesnotenabled"); 71 $errorcode = 1; 72 } 73 } 74 75 /// Check for timed out sessions 76 if (!empty($SESSION->has_timed_out)) { 77 $session_has_timed_out = true; 78 unset($SESSION->has_timed_out); 79 } else { 80 $session_has_timed_out = false; 81 } 82 83 $frm = false; 84 $user = false; 85 86 $authsequence = get_enabled_auth_plugins(); // Auths, in sequence. 87 foreach($authsequence as $authname) { 88 $authplugin = get_auth_plugin($authname); 89 // The auth plugin's loginpage_hook() can eventually set $frm and/or $user. 90 $authplugin->loginpage_hook(); 91 } 92 93 94 /// Define variables used in page 95 $site = get_site(); 96 97 // Ignore any active pages in the navigation/settings. 98 // We do this because there won't be an active page there, and by ignoring the active pages the 99 // navigation and settings won't be initialised unless something else needs them. 100 $PAGE->navbar->ignore_active(); 101 $loginsite = get_string("loginsite"); 102 $PAGE->navbar->add($loginsite); 103 104 if ($user !== false or $frm !== false or $errormsg !== '') { 105 // some auth plugin already supplied full user, fake form data or prevented user login with error message 106 107 } else if (!empty($SESSION->wantsurl) && file_exists($CFG->dirroot.'/login/weblinkauth.php')) { 108 // Handles the case of another Moodle site linking into a page on this site 109 //TODO: move weblink into own auth plugin 110 include($CFG->dirroot.'/login/weblinkauth.php'); 111 if (function_exists('weblink_auth')) { 112 $user = weblink_auth($SESSION->wantsurl); 113 } 114 if ($user) { 115 $frm->username = $user->username; 116 } else { 117 $frm = data_submitted(); 118 } 119 120 } else { 121 $frm = data_submitted(); 122 } 123 124 // Restore the #anchor to the original wantsurl. Note that this 125 // will only work for internal auth plugins, SSO plugins such as 126 // SAML / CAS / OIDC will have to handle this correctly directly. 127 if ($anchor && isset($SESSION->wantsurl) && strpos($SESSION->wantsurl, '#') === false) { 128 $wantsurl = new moodle_url($SESSION->wantsurl); 129 $wantsurl->set_anchor(substr($anchor, 1)); 130 $SESSION->wantsurl = $wantsurl->out(); 131 } 132 133 /// Check if the user has actually submitted login data to us 134 135 if ($frm and isset($frm->username)) { // Login WITH cookies 136 137 $frm->username = trim(core_text::strtolower($frm->username)); 138 139 if (is_enabled_auth('none') ) { 140 if ($frm->username !== core_user::clean_field($frm->username, 'username')) { 141 $errormsg = get_string('username').': '.get_string("invalidusername"); 142 $errorcode = 2; 143 $user = null; 144 } 145 } 146 147 if ($user) { 148 // The auth plugin has already provided the user via the loginpage_hook() called above. 149 } else if (($frm->username == 'guest') and empty($CFG->guestloginbutton)) { 150 $user = false; /// Can't log in as guest if guest button is disabled 151 $frm = false; 152 } else { 153 if (empty($errormsg)) { 154 $logintoken = isset($frm->logintoken) ? $frm->logintoken : ''; 155 $loginrecaptcha = $frm->{'g-recaptcha-response'} ?? false; 156 $user = authenticate_user_login($frm->username, $frm->password, false, $errorcode, $logintoken, $loginrecaptcha); 157 } 158 } 159 160 // Intercept 'restored' users to provide them with info & reset password 161 if (!$user and $frm and is_restored_user($frm->username)) { 162 $PAGE->set_title(get_string('restoredaccount')); 163 $PAGE->set_heading($site->fullname); 164 echo $OUTPUT->header(); 165 echo $OUTPUT->heading(get_string('restoredaccount')); 166 echo $OUTPUT->box(get_string('restoredaccountinfo'), 'generalbox boxaligncenter'); 167 require_once ('restored_password_form.php'); // Use our "supplanter" login_forgot_password_form. MDL-20846 168 $form = new login_forgot_password_form('forgot_password.php', array('username' => $frm->username)); 169 $form->display(); 170 echo $OUTPUT->footer(); 171 die; 172 } 173 174 if ($user) { 175 176 // language setup 177 if (isguestuser($user)) { 178 // no predefined language for guests - use existing session or default site lang 179 unset($user->lang); 180 181 } else if (!empty($user->lang)) { 182 // unset previous session language - use user preference instead 183 unset($SESSION->lang); 184 } 185 186 if (empty($user->confirmed)) { // This account was never confirmed 187 $PAGE->set_title(get_string("mustconfirm")); 188 $PAGE->set_heading($site->fullname); 189 echo $OUTPUT->header(); 190 echo $OUTPUT->heading(get_string("mustconfirm")); 191 if ($resendconfirmemail) { 192 if (!send_confirmation_email($user)) { 193 echo $OUTPUT->notification(get_string('emailconfirmsentfailure'), \core\output\notification::NOTIFY_ERROR); 194 } else { 195 echo $OUTPUT->notification(get_string('emailconfirmsentsuccess'), \core\output\notification::NOTIFY_SUCCESS); 196 } 197 } 198 echo $OUTPUT->box(get_string("emailconfirmsent", "", s($user->email)), "generalbox boxaligncenter"); 199 $resendconfirmurl = new moodle_url('/login/index.php', 200 [ 201 'username' => $frm->username, 202 'password' => $frm->password, 203 'resendconfirmemail' => true, 204 'logintoken' => \core\session\manager::get_login_token() 205 ] 206 ); 207 echo $OUTPUT->single_button($resendconfirmurl, get_string('emailconfirmationresend')); 208 echo $OUTPUT->footer(); 209 die; 210 } 211 212 /// Let's get them all set up. 213 complete_user_login($user); 214 215 \core\session\manager::apply_concurrent_login_limit($user->id, session_id()); 216 217 // sets the username cookie 218 if (!empty($CFG->nolastloggedin)) { 219 // do not store last logged in user in cookie 220 // auth plugins can temporarily override this from loginpage_hook() 221 // do not save $CFG->nolastloggedin in database! 222 223 } else if (empty($CFG->rememberusername)) { 224 // no permanent cookies, delete old one if exists 225 set_moodle_cookie(''); 226 227 } else { 228 set_moodle_cookie($USER->username); 229 } 230 231 $urltogo = core_login_get_return_url(); 232 233 /// check if user password has expired 234 /// Currently supported only for ldap-authentication module 235 $userauth = get_auth_plugin($USER->auth); 236 if (!isguestuser() and !empty($userauth->config->expiration) and $userauth->config->expiration == 1) { 237 $externalchangepassword = false; 238 if ($userauth->can_change_password()) { 239 $passwordchangeurl = $userauth->change_password_url(); 240 if (!$passwordchangeurl) { 241 $passwordchangeurl = $CFG->wwwroot.'/login/change_password.php'; 242 } else { 243 $externalchangepassword = true; 244 } 245 } else { 246 $passwordchangeurl = $CFG->wwwroot.'/login/change_password.php'; 247 } 248 $days2expire = $userauth->password_expire($USER->username); 249 $PAGE->set_title($loginsite); 250 $PAGE->set_heading("$site->fullname"); 251 if (intval($days2expire) > 0 && intval($days2expire) < intval($userauth->config->expiration_warning)) { 252 echo $OUTPUT->header(); 253 echo $OUTPUT->confirm(get_string('auth_passwordwillexpire', 'auth', $days2expire), $passwordchangeurl, $urltogo); 254 echo $OUTPUT->footer(); 255 exit; 256 } elseif (intval($days2expire) < 0 ) { 257 if ($externalchangepassword) { 258 // We end the session if the change password form is external. This prevents access to the site 259 // until the password is correctly changed. 260 require_logout(); 261 } else { 262 // If we use the standard change password form, this user preference will be reset when the password 263 // is changed. Until then it will prevent access to the site. 264 set_user_preference('auth_forcepasswordchange', 1, $USER); 265 } 266 echo $OUTPUT->header(); 267 echo $OUTPUT->confirm(get_string('auth_passwordisexpired', 'auth'), $passwordchangeurl, $urltogo); 268 echo $OUTPUT->footer(); 269 exit; 270 } 271 } 272 273 // Discard any errors before the last redirect. 274 unset($SESSION->loginerrormsg); 275 unset($SESSION->logininfomsg); 276 277 // test the session actually works by redirecting to self 278 $SESSION->wantsurl = $urltogo; 279 redirect(new moodle_url(get_login_url(), array('testsession'=>$USER->id))); 280 281 } else { 282 if (empty($errormsg)) { 283 if ($errorcode == AUTH_LOGIN_UNAUTHORISED) { 284 $errormsg = get_string("unauthorisedlogin", "", $frm->username); 285 } else if ($errorcode == AUTH_LOGIN_FAILED_RECAPTCHA) { 286 $errormsg = get_string('missingrecaptchachallengefield'); 287 } else { 288 $errormsg = get_string("invalidlogin"); 289 $errorcode = 3; 290 } 291 } 292 } 293 } 294 295 /// Detect problems with timedout sessions 296 if ($session_has_timed_out and !data_submitted()) { 297 $errormsg = get_string('sessionerroruser', 'error'); 298 $errorcode = 4; 299 } 300 301 /// First, let's remember where the user was trying to get to before they got here 302 303 if (empty($SESSION->wantsurl)) { 304 $SESSION->wantsurl = null; 305 $referer = get_local_referer(false); 306 if ($referer && 307 $referer != $CFG->wwwroot && 308 $referer != $CFG->wwwroot . '/' && 309 $referer != $CFG->wwwroot . '/login/' && 310 strpos($referer, $CFG->wwwroot . '/login/?') !== 0 && 311 strpos($referer, $CFG->wwwroot . '/login/index.php') !== 0) { // There might be some extra params such as ?lang=. 312 $SESSION->wantsurl = $referer; 313 } 314 } 315 316 /// Redirect to alternative login URL if needed 317 if (!empty($CFG->alternateloginurl)) { 318 $loginurl = new moodle_url($CFG->alternateloginurl); 319 320 $loginurlstr = $loginurl->out(false); 321 322 if ($SESSION->wantsurl != '' && strpos($SESSION->wantsurl, $loginurlstr) === 0) { 323 // We do not want to return to alternate url. 324 $SESSION->wantsurl = null; 325 } 326 327 // If error code then add that to url. 328 if ($errorcode) { 329 $loginurl->param('errorcode', $errorcode); 330 } 331 332 redirect($loginurl->out(false)); 333 } 334 335 /// Generate the login page with forms 336 337 if (!isset($frm) or !is_object($frm)) { 338 $frm = new stdClass(); 339 } 340 341 if (empty($frm->username) && $authsequence[0] != 'shibboleth') { // See bug 5184 342 if (!empty($_GET["username"])) { 343 // we do not want data from _POST here 344 $frm->username = clean_param($_GET["username"], PARAM_RAW); // we do not want data from _POST here 345 } else { 346 $frm->username = get_moodle_cookie(); 347 } 348 349 $frm->password = ""; 350 } 351 352 if (!empty($SESSION->loginerrormsg) || !empty($SESSION->logininfomsg)) { 353 // We had some messages before redirect, show them now. 354 $errormsg = $SESSION->loginerrormsg ?? ''; 355 $infomsg = $SESSION->logininfomsg ?? ''; 356 unset($SESSION->loginerrormsg); 357 unset($SESSION->logininfomsg); 358 359 } else if ($testsession) { 360 // No need to redirect here. 361 unset($SESSION->loginerrormsg); 362 unset($SESSION->logininfomsg); 363 364 } else if ($errormsg or !empty($frm->password)) { 365 // We must redirect after every password submission. 366 if ($errormsg) { 367 $SESSION->loginerrormsg = $errormsg; 368 } 369 redirect(new moodle_url('/login/index.php')); 370 } 371 372 $PAGE->set_title($loginsite); 373 $PAGE->set_heading("$site->fullname"); 374 375 echo $OUTPUT->header(); 376 377 if (isloggedin() and !isguestuser()) { 378 // prevent logging when already logged in, we do not want them to relogin by accident because sesskey would be changed 379 echo $OUTPUT->box_start(); 380 $logout = new single_button(new moodle_url('/login/logout.php', array('sesskey'=>sesskey(),'loginpage'=>1)), get_string('logout'), 'post'); 381 $continue = new single_button(new moodle_url('/'), get_string('cancel'), 'get'); 382 echo $OUTPUT->confirm(get_string('alreadyloggedin', 'error', fullname($USER)), $logout, $continue); 383 echo $OUTPUT->box_end(); 384 } else { 385 $loginform = new \core_auth\output\login($authsequence, $frm->username); 386 $loginform->set_error($errormsg); 387 $loginform->set_info($infomsg); 388 echo $OUTPUT->render($loginform); 389 } 390 391 echo $OUTPUT->footer();
title
Description
Body
title
Description
Body
title
Description
Body
title
Body