Rev 1 | Autoría | Comparar con el anterior | Ultima modificación | Ver Log |
<?php
// Este archivo es parte de Moodle - http://moodle.org/
//
// Moodle es software libre: puedes redistribuirlo y/o modificarlo
// bajo los términos de la Licencia Pública General GNU publicada por
// la Free Software Foundation, ya sea la versión 3 de la Licencia, o
// (a tu elección) cualquier versión posterior.
//
// Moodle se distribuye con la esperanza de que sea útil,
// pero SIN NINGUNA GARANTÍA; sin siquiera la garantía implícita de
// COMERCIABILIDAD o IDONEIDAD PARA UN PROPÓSITO PARTICULAR. Ver la
// Licencia Pública General GNU para más detalles.
//
// Deberías haber recibido una copia de la Licencia Pública General GNU
// junto con Moodle. Si no, ve <http://www.gnu.org/licenses/>.
/**
* Página principal de inicio de sesión de Moodle.
* Este archivo maneja todo el proceso de autenticación de usuarios,
* incluyendo la validación de credenciales, manejo de sesiones,
* redirecciones y mensajes de error.
*
* @package core
* @subpackage auth
* @copyright 1999 onwards Martin Dougiamas http://dougiamas.com
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
// Incluir archivos de configuración y librerías necesarias
require('../config.php');
require_once('lib.php');
// Verificar si se requiere una actualización mayor del sistema
// Si es así, redirigir al usuario a la página de actualización
redirect_if_major_upgrade_required();
// ============================================================================
// PARÁMETROS DE LA PÁGINA DE INICIO DE SESIÓN
// ============================================================================
// Parámetros opcionales que controlan el comportamiento del inicio de sesión
$testsession = optional_param('testsession', 0, PARAM_INT); // Verifica el funcionamiento correcto de la sesión
$anchor = optional_param('anchor', '', PARAM_RAW); // Mantiene la posición del ancla en la URL de destino
$loginredirect = optional_param('loginredirect', 1, PARAM_BOOL); // Controla la redirección a URL de login alternativo
$resendconfirmemail = optional_param('resendconfirmemail', false, PARAM_BOOL); // Permite reenviar email de confirmación
// Verificación especial para sitios Behat (entorno de pruebas)
// Esto podría ser seguro para sitios no-Behat, pero por ahora solo lo permitimos en sitios Behat
if (defined('BEHAT_SITE_RUNNING') && BEHAT_SITE_RUNNING) {
$wantsurl = optional_param('wantsurl', '', PARAM_LOCALURL); // Sobrescribe $SESSION->wantsurl si se proporciona
if ($wantsurl !== '') {
$SESSION->wantsurl = (new moodle_url($wantsurl))->out(false);
}
}
// Configuración del contexto y la página
$context = context_system::instance();
$PAGE->set_url("$CFG->wwwroot/login/index.php");
$PAGE->set_context($context);
$PAGE->set_pagelayout('login');
// ============================================================================
// CONFIGURACIÓN INICIAL Y VARIABLES
// ============================================================================
// Inicialización de variables para el manejo de mensajes y errores
$errormsg = ''; // Almacena mensajes de error para mostrar al usuario
$infomsg = ''; // Almacena mensajes informativos para mostrar al usuario
$errorcode = 0; // Código numérico que identifica el tipo de error
// ============================================================================
// VERIFICACIÓN DE SESIÓN
// ============================================================================
// Prueba de funcionamiento de la sesión
if ($testsession) {
if ($testsession == $USER->id) {
// Si la sesión es válida, redirigir a la URL deseada
if (isset($SESSION->wantsurl)) {
$urltogo = $SESSION->wantsurl;
} else {
$urltogo = $CFG->wwwroot . '/';
}
unset($SESSION->wantsurl);
redirect($urltogo);
} else {
// Si la sesión no es válida, mostrar error de cookies
$errormsg = get_string("cookiesnotenabled");
$errorcode = 1;
}
}
// ============================================================================
// MANEJO DE SESIONES EXPIRADAS
// ============================================================================
// Verificar si la sesión actual ha expirado
if (!empty($SESSION->has_timed_out)) {
$session_has_timed_out = true;
unset($SESSION->has_timed_out);
} else {
$session_has_timed_out = false;
}
// Inicialización de variables para el formulario y usuario
$frm = false;
$user = false;
// Obtener la secuencia de plugins de autenticación habilitados
$authsequence = get_enabled_auth_plugins();
foreach ($authsequence as $authname) {
$authplugin = get_auth_plugin($authname);
// El hook loginpage_hook() del plugin de autenticación puede establecer $frm y/o $user
$authplugin->loginpage_hook();
}
// ============================================================================
// CONFIGURACIÓN DEL SITIO Y NAVEGACIÓN
// ============================================================================
// Obtener información del sitio
$site = get_site();
// Ignorar páginas activas en la navegación/configuración
$PAGE->navbar->ignore_active();
$loginsite = get_string("loginsite");
$PAGE->navbar->add($loginsite);
// ============================================================================
// PROCESO DE AUTENTICACIÓN
// ============================================================================
// Verificar si algún plugin de autenticación ya proporcionó el usuario completo
if ($user !== false or $frm !== false or $errormsg !== '') {
// El plugin de autenticación ya proporcionó el usuario completo, datos del formulario falso
// o impidió el inicio de sesión con mensaje de error
} else if (!empty($SESSION->wantsurl) && file_exists($CFG->dirroot . '/login/weblinkauth.php')) {
// Maneja el caso de otro sitio Moodle vinculando a una página en este sitio
include($CFG->dirroot . '/login/weblinkauth.php');
if (function_exists('weblink_auth')) {
$user = weblink_auth($SESSION->wantsurl);
}
if ($user) {
$frm->username = $user->username;
} else {
$frm = data_submitted();
}
} else {
$frm = data_submitted();
}
// Restaurar el #anchor a la wantsurl original
if ($anchor && isset($SESSION->wantsurl) && strpos($SESSION->wantsurl, '#') === false) {
$wantsurl = new moodle_url($SESSION->wantsurl);
$wantsurl->set_anchor(substr($anchor, 1));
$SESSION->wantsurl = $wantsurl->out();
}
// ============================================================================
// VERIFICACIÓN DE CREDENCIALES
// ============================================================================
// Verificar si el usuario ha enviado datos de inicio de sesión
if ($frm and isset($frm->username)) {
// Normalizar el nombre de usuario
$frm->username = trim(core_text::strtolower($frm->username));
// Verificar la autenticación 'none' si está habilitada
if (is_enabled_auth('none')) {
if ($frm->username !== core_user::clean_field($frm->username, 'username')) {
$errormsg = get_string('username') . ': ' . get_string("invalidusername");
$errorcode = 2;
$user = null;
}
}
// Verificar si el usuario es invitado
if ($user) {
// El plugin de autenticación ya proporcionó el usuario
} else if (($frm->username == 'guest') and empty($CFG->guestloginbutton)) {
$user = false; // No se puede iniciar sesión como invitado si el botón de invitado está deshabilitado
$frm = false;
} else {
if (empty($errormsg)) {
// Intentar autenticar al usuario
$logintoken = isset($frm->logintoken) ? $frm->logintoken : '';
$loginrecaptcha = login_captcha_enabled() ? $frm->{'g-recaptcha-response'} ?? '' : false;
$user = authenticate_user_login($frm->username, $frm->password, false, $errorcode, $logintoken, $loginrecaptcha);
}
}
// ============================================================================
// MANEJO DE USUARIOS RESTAURADOS
// ============================================================================
// Procesar usuarios que han sido restaurados desde una copia de seguridad
if (!$user and $frm and is_restored_user($frm->username)) {
$PAGE->set_title(get_string('restoredaccount'));
$PAGE->set_heading($site->fullname);
echo $OUTPUT->header();
echo $OUTPUT->heading(get_string('restoredaccount'));
echo $OUTPUT->box(get_string('restoredaccountinfo'), 'generalbox boxaligncenter');
require_once('restored_password_form.php');
$form = new login_forgot_password_form('forgot_password.php', array('username' => $frm->username));
$form->display();
echo $OUTPUT->footer();
die;
}
// ============================================================================
// CONFIRMACIÓN DE CUENTA
// ============================================================================
if ($user) {
// Configuración del idioma
if (isguestuser($user)) {
// Sin idioma predefinido para invitados - usar sesión existente o idioma predeterminado del sitio
unset($user->lang);
} else if (!empty($user->lang)) {
// Desactivar idioma de sesión anterior - usar preferencia del usuario
unset($SESSION->lang);
}
// Verificar si la cuenta nunca fue confirmada
if (empty($user->confirmed)) {
$PAGE->set_title(get_string("mustconfirm"));
$PAGE->set_heading($site->fullname);
echo $OUTPUT->header();
echo $OUTPUT->heading(get_string("mustconfirm"));
if ($resendconfirmemail) {
if (!send_confirmation_email($user)) {
echo $OUTPUT->notification(get_string('emailconfirmsentfailure'), \core\output\notification::NOTIFY_ERROR);
} else {
echo $OUTPUT->notification(get_string('emailconfirmsentsuccess'), \core\output\notification::NOTIFY_SUCCESS);
}
}
echo $OUTPUT->box(get_string("emailconfirmsent", "", s($user->email)), "generalbox boxaligncenter");
$resendconfirmurl = new moodle_url(
'/login/index.php',
[
'username' => $frm->username,
'password' => $frm->password,
'resendconfirmemail' => true,
'logintoken' => \core\session\manager::get_login_token()
]
);
echo $OUTPUT->single_button($resendconfirmurl, get_string('emailconfirmationresend'));
echo $OUTPUT->footer();
die;
}
// ============================================================================
// COMPLETAR INICIO DE SESIÓN
// ============================================================================
// Completar el proceso de inicio de sesión
complete_user_login($user);
// Aplicar límite de inicio de sesión concurrente
\core\session\manager::apply_concurrent_login_limit($user->id, session_id());
// Configurar cookie de nombre de usuario
if (!empty($CFG->nolastloggedin)) {
// No almacenar último usuario conectado en cookie
} else if (empty($CFG->rememberusername)) {
// Sin cookies permanentes, eliminar la anterior si existe
set_moodle_cookie('');
} else {
set_moodle_cookie($USER->username);
}
// Obtener URL de redirección
$urltogo = core_login_get_return_url();
// ============================================================================
// VERIFICACIÓN DE CONTRASEÑAS EXPIRADAS
// ============================================================================
// Verificar si la contraseña del usuario ha expirado (solo para autenticación LDAP)
$userauth = get_auth_plugin($USER->auth);
if (!isguestuser() and !empty($userauth->config->expiration) and $userauth->config->expiration == 1) {
$externalchangepassword = false;
if ($userauth->can_change_password()) {
$passwordchangeurl = $userauth->change_password_url();
if (!$passwordchangeurl) {
$passwordchangeurl = $CFG->wwwroot . '/login/change_password.php';
} else {
$externalchangepassword = true;
}
} else {
$passwordchangeurl = $CFG->wwwroot . '/login/change_password.php';
}
$days2expire = $userauth->password_expire($USER->username);
$PAGE->set_title($loginsite);
$PAGE->set_heading("$site->fullname");
if (intval($days2expire) > 0 && intval($days2expire) < intval($userauth->config->expiration_warning)) {
echo $OUTPUT->header();
echo $OUTPUT->confirm(get_string('auth_passwordwillexpire', 'auth', $days2expire), $passwordchangeurl, $urltogo);
echo $OUTPUT->footer();
exit;
} elseif (intval($days2expire) < 0) {
if ($externalchangepassword) {
// Cerrar sesión si el formulario de cambio de contraseña es externo
require_logout();
} else {
// Forzar cambio de contraseña si se usa el formulario estándar
set_user_preference('auth_forcepasswordchange', 1, $USER);
}
echo $OUTPUT->header();
echo $OUTPUT->confirm(get_string('auth_passwordisexpired', 'auth'), $passwordchangeurl, $urltogo);
echo $OUTPUT->footer();
exit;
}
}
// Limpiar mensajes de error antes de la última redirección
unset($SESSION->loginerrormsg);
unset($SESSION->logininfomsg);
// Descartar loginredirect si estamos redirigiendo
unset($SESSION->loginredirect);
// Probar que la sesión funciona redirigiendo a sí mismo
$SESSION->wantsurl = $urltogo;
redirect(new moodle_url(get_login_url(), array('testsession' => $USER->id)));
} else {
// Manejo de errores de autenticación
if (empty($errormsg)) {
if ($errorcode == AUTH_LOGIN_UNAUTHORISED) {
$errormsg = get_string("unauthorisedlogin", "", $frm->username);
} else if ($errorcode == AUTH_LOGIN_FAILED_RECAPTCHA) {
$errormsg = get_string('missingrecaptchachallengefield');
} else {
$errormsg = get_string("invalidlogin");
$errorcode = 3;
}
}
}
}
// ============================================================================
// DETECCIÓN DE PROBLEMAS CON SESIONES
// ============================================================================
// Detectar problemas con sesiones con tiempo de espera agotado
if ($session_has_timed_out and !data_submitted()) {
$errormsg = get_string('sessionerroruser', 'error');
$errorcode = 4;
}
// ============================================================================
// MANEJO DE URL DE DESTINO
// ============================================================================
// Recordar dónde estaba intentando llegar el usuario antes de llegar aquí
if (empty($SESSION->wantsurl)) {
$SESSION->wantsurl = null;
$referer = get_local_referer(false);
if (
$referer &&
$referer != $CFG->wwwroot &&
$referer != $CFG->wwwroot . '/' &&
$referer != $CFG->wwwroot . '/login/' &&
strpos($referer, $CFG->wwwroot . '/login/?') !== 0 &&
strpos($referer, $CFG->wwwroot . '/login/index.php') !== 0
) {
$SESSION->wantsurl = $referer;
}
}
// Verificar si loginredirect está establecido en la SESSION
if ($errorcode && isset($SESSION->loginredirect)) {
$loginredirect = $SESSION->loginredirect;
}
$SESSION->loginredirect = $loginredirect;
// ============================================================================
// REDIRECCIÓN A URL DE INICIO DE SESIÓN ALTERNATIVA
// ============================================================================
// Redirigir a URL de inicio de sesión alternativa si es necesario
if (!empty($CFG->alternateloginurl) && $loginredirect) {
$loginurl = new moodle_url($CFG->alternateloginurl);
$loginurlstr = $loginurl->out(false);
if ($SESSION->wantsurl != '' && strpos($SESSION->wantsurl, $loginurlstr) === 0) {
// No queremos volver a la URL alternativa
$SESSION->wantsurl = null;
}
// Si hay código de error, agregarlo a la URL
if ($errorcode) {
$loginurl->param('errorcode', $errorcode);
}
redirect($loginurl->out(false));
}
// ============================================================================
// GENERACIÓN DE LA PÁGINA DE INICIO DE SESIÓN
// ============================================================================
// Inicializar el objeto del formulario si no existe
if (!isset($frm) or !is_object($frm)) {
$frm = new stdClass();
}
// Configurar valores predeterminados del formulario
if (empty($frm->username) && $authsequence[0] != 'shibboleth') {
if (!empty($_GET["username"])) {
$frm->username = clean_param($_GET["username"], PARAM_RAW);
} else {
$frm->username = get_moodle_cookie();
}
$frm->password = "";
}
// Manejar mensajes de error e información
if (!empty($SESSION->loginerrormsg) || !empty($SESSION->logininfomsg)) {
$errormsg = $SESSION->loginerrormsg ?? '';
$infomsg = $SESSION->logininfomsg ?? '';
unset($SESSION->loginerrormsg);
unset($SESSION->logininfomsg);
} else if ($testsession) {
unset($SESSION->loginerrormsg);
unset($SESSION->logininfomsg);
} else if ($errormsg or !empty($frm->password)) {
if ($errormsg) {
$SESSION->loginerrormsg = $errormsg;
}
$loginurl = new moodle_url('/login/index.php');
$loginurl->param('loginredirect', $SESSION->loginredirect);
redirect($loginurl->out(false));
}
// ============================================================================
// RENDERIZADO DE LA PÁGINA
// ============================================================================
// Configurar título y encabezado de la página
$PAGE->set_title($loginsite);
$PAGE->set_heading("$site->fullname");
// Mostrar el encabezado de la página
echo $OUTPUT->header();
// Verificar el estado de la sesión del usuario
if (isloggedin() and !isguestuser()) {
// Si el usuario ya está conectado, mostrar mensaje y opciones
echo $OUTPUT->box_start();
$logout = new single_button(new moodle_url('/login/logout.php', array('sesskey' => sesskey(), 'loginpage' => 1)), get_string('logout'), 'post');
$continue = new single_button(new moodle_url('/'), get_string('cancel'), 'get');
echo $OUTPUT->confirm(get_string('alreadyloggedin', 'error', fullname($USER)), $logout, $continue);
echo $OUTPUT->box_end();
} else {
// Mostrar el formulario de inicio de sesión
$loginform = new \core_auth\output\login($authsequence, $frm->username);
$loginform->set_error($errormsg);
$loginform->set_info($infomsg);
echo $OUTPUT->render($loginform);
}
// Mostrar el pie de página
echo $OUTPUT->footer();