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