Proyectos de Subversion Moodle

Rev

Rev 1400 | Rev 1402 | Ir a la última revisión | Mostrar el archivo completo | | | Autoría | Ultima modificación | Ver Log |

Rev 1400 Rev 1401
Línea 22... Línea 22...
22
require_once($CFG->libdir . '/gdlib.php');
22
require_once($CFG->libdir . '/gdlib.php');
23
require_once($CFG->dirroot . '/user/lib.php');
23
require_once($CFG->dirroot . '/user/lib.php');
24
require_once(__DIR__ . '/rsa.php');
24
require_once(__DIR__ . '/rsa.php');
25
require_once(__DIR__ . '/lib.php');
25
require_once(__DIR__ . '/lib.php');
Línea 26... Línea -...
26
 
-
 
27
/**
26
 
28
 * Valida los parámetros de seguridad de la petición
27
// Obtención y sanitización de parámetros de la petición
29
 * @param array $params Parámetros de la petición
28
$username   = trim(isset($_REQUEST['username']) ? filter_var($_REQUEST['username'], FILTER_SANITIZE_STRING) : '');
-
 
29
$password   = trim(isset($_REQUEST['password']) ? filter_var($_REQUEST['password'], FILTER_SANITIZE_STRING) : '');
-
 
30
$timestamp  = trim(isset($_REQUEST['timestamp']) ? filter_var($_REQUEST['timestamp'], FILTER_SANITIZE_STRING) : '');
-
 
31
$rand       = intval(isset($_REQUEST['rand']) ? filter_var($_REQUEST['rand'], FILTER_SANITIZE_NUMBER_INT) : 0, 10);
-
 
32
$data       = trim(isset($_REQUEST['data']) ? filter_var($_REQUEST['data'], FILTER_SANITIZE_STRING) : '');
30
 * @return array|false Array con los parámetros validados o false si hay error
33
 
-
 
34
/*
-
 
35
$data = '';
-
 
36
$input = fopen("php://input", "r");
-
 
37
 
31
 */
38
 
32
function validateSecurityParams($params)
39
while ($line = fread($input, 1024))
33
{
-
 
34
    $username = trim(isset($params['username']) ? filter_var($params['username'], FILTER_SANITIZE_STRING) : '');
-
 
35
    $password = trim(isset($params['password']) ? filter_var($params['password'], FILTER_SANITIZE_STRING) : '');
-
 
36
    $timestamp = trim(isset($params['timestamp']) ? filter_var($params['timestamp'], FILTER_SANITIZE_STRING) : '');
40
{
-
 
41
    $data .= $line; 
37
    $rand = intval(isset($params['rand']) ? filter_var($params['rand'], FILTER_SANITIZE_NUMBER_INT) : 0, 10);
42
}
Línea -... Línea 43...
-
 
43
fclose($input);*/
38
    $data = trim(isset($params['data']) ? filter_var($params['data'], FILTER_SANITIZE_STRING) : '');
44
 
-
 
45
/*
-
 
46
echo 'username = '. $username . PHP_EOL;
39
 
47
echo 'password = '. $password . PHP_EOL;
40
    if (empty($username) || empty($password) || empty($timestamp) || empty($rand) || !is_integer($rand)) {
48
echo 'rand = '. $rand . PHP_EOL;
Línea 41... Línea -...
41
        return ['error' => 'ERROR_SECURITY1', 'message' => 'Missing or invalid security parameters'];
-
 
42
    }
-
 
43
 
-
 
Línea -... Línea 49...
-
 
49
echo 'timestamp = '. $timestamp . PHP_EOL;
44
    if ($username != LLWS_USERNAME) {
50
echo 'data = '. $data . PHP_EOL;
45
        return ['error' => 'ERROR_SECURITY2', 'message' => 'Invalid username'];
-
 
46
    }
51
 
47
 
-
 
Línea 48... Línea 52...
48
    $dt = \DateTime::createFromFormat('Y-m-d\TH:i:s', $timestamp);
52
 
49
    if (!$dt) {
53
/*
50
        return ['error' => 'ERROR_SECURITY3', 'message' => 'Invalid timestamp format'];
54
list($usec, $sec) = explode(' ', microtime());
51
    }
-
 
52
 
55
$seed = intval($sec + ((float) $usec * 100000));
53
    $t0 = $dt->getTimestamp();
-
 
54
    $t1 = strtotime('-5 minutes');
-
 
Línea -... Línea 56...
-
 
56
 
55
    $t2 = strtotime('+5 minutes');
57
$username   = LLWS_USERNAME;
-
 
58
$timestamp  = date('Y-m-d\TH:i:s');
56
 
59
mt_srand($seed, MT_RAND_MT19937);
57
    /* if ($t0 < $t1 || $t0 > $t2) {
60
$rand =  mt_rand();
Línea 58... Línea -...
58
        return ['error' => 'ERROR_SECURITY4', 'message' => 'Timestamp out of valid range'];
-
 
59
    } */
61
 
60
 
62
$password   = LLWS_PASSWORD;
61
    if (!password_verify($username . '-' . LLWS_PASSWORD . '-' . $rand . '-' . $timestamp, $password)) {
63
$password  = password_hash($username.'-'. $password. '-' . $rand. '-' . $timestamp, PASSWORD_DEFAULT);
62
        return ['error' => 'ERROR_SECURITY5', 'message' => 'Invalid password'];
-
 
63
    }
-
 
64
 
64
 
65
    return [
65
$data       = $rsa->encrypt(json_encode(['email' => 'usuario4@test.com', 'first_name' => 'usuario4', 'last_name' => 'test']));
Línea 66... Línea -...
66
        'username' => $username,
-
 
67
        'password' => $password,
66
*/
68
        'timestamp' => $timestamp,
67
 
69
        'rand' => $rand,
68
// Validación de parámetros de seguridad
70
        'data' => $data
69
if (empty($username) || empty($password) || empty($timestamp) || empty($rand) || !is_integer($rand)) {
71
    ];
-
 
72
}
70
    echo json_encode(['success' => false, 'data' => 'ERROR_SECURITY1']);
73
 
-
 
74
/**
-
 
75
 * Procesa y decodifica los datos de la petición
-
 
Línea 76... Línea 71...
76
 * @param string $data Datos encriptados
71
    exit;
-
 
72
}
77
 * @return array|false Array con los datos decodificados o false si hay error
73
 
78
 */
74
// Validación del nombre de usuario
79
function processRequestData($data)
75
if ($username != LLWS_USERNAME) {
-
 
76
    echo json_encode(['success' => false, 'data' => 'ERROR_SECURITY2']);
Línea 80... Línea 77...
80
{
77
    exit;
81
    if (empty($data)) {
78
}
82
        return ['error' => 'ERROR_PARAMETERS1', 'message' => 'No data provided'];
79
 
83
    }
80
// Validación del formato del timestamp
-
 
81
$dt = \DateTime::createFromFormat('Y-m-d\TH:i:s', $timestamp);
84
 
82
if (!$dt) {
85
    $data = base64_decode($data);
83
    echo json_encode(['success' => false, 'data' => 'ERROR_SECURITY3']);
86
    if (empty($data)) {
84
    exit;
-
 
85
}
Línea 87... Línea 86...
87
        return ['error' => 'ERROR_PARAMETERS2', 'message' => 'Invalid base64 data'];
86
 
88
    }
87
// Validación del rango de tiempo del timestamp (±5 minutos)
89
 
88
$t0 = $dt->getTimestamp();
90
    try {
89
$t1 = strtotime('-5 minutes');
-
 
90
$t2 = strtotime('+5 minutes');
Línea 91... Línea 91...
91
        $rsa = new rsa();
91
 
92
        $rsa->setKeys(LLWS_RSA_N, LLWS_RSA_D, LLWS_RSA_E);
92
if ($t0 < $t1 || $t0 > $t2) {
93
        $data = $rsa->decrypt($data);
93
    //echo json_encode(['success' => false, 'data' => 'ERROR_SECURITY4']) ;
-
 
94
    //exit;
-
 
95
}
Línea 94... Línea 96...
94
    } catch (Throwable $e) {
96
 
-
 
97
// Validación de la contraseña
-
 
98
if (!password_verify($username . '-' . LLWS_PASSWORD . '-' . $rand . '-' . $timestamp, $password)) {
95
        return ['error' => 'ERROR_PARAMETERS3', 'message' => 'Decryption failed'];
99
    echo json_encode(['success' => false, 'data' => 'ERROR_SECURITY5']);
96
    }
100
    exit;
-
 
101
}
Línea -... Línea 102...
-
 
102
 
97
 
103
// Validación de datos
98
    $data = (array) json_decode($data);
104
if (empty($data)) {
99
    if (empty($data)) {
105
    echo json_encode(['success' => false, 'data' => 'ERROR_PARAMETERS1']);
100
        return ['error' => 'ERROR_PARAMETERS4', 'message' => 'Invalid JSON data'];
106
    exit;
101
    }
107
}
102
 
108
 
103
    $email = trim(isset($data['email']) ? filter_var($data['email'], FILTER_SANITIZE_EMAIL) : '');
109
// Decodificación de datos en base64
104
    $first_name = trim(isset($data['first_name']) ? filter_var($data['first_name'], FILTER_SANITIZE_STRING) : '');
110
$data = base64_decode($data);
Línea 105... Línea -...
105
    $last_name = trim(isset($data['last_name']) ? filter_var($data['last_name'], FILTER_SANITIZE_STRING) : '');
-
 
106
 
111
if (empty($data)) {
107
    if (!filter_var($email, FILTER_VALIDATE_EMAIL) || empty($first_name) || empty($last_name)) {
112
    echo json_encode(['success' => false, 'data' => 'ERROR_PARAMETERS2']);
-
 
113
    exit;
108
        return ['error' => 'ERROR_PARAMETERS5', 'message' => 'Invalid user data'];
114
}
109
    }
115
 
110
 
-
 
111
    return [
116
// Desencriptación de datos usando RSA
112
        'email' => $email,
-
 
Línea 113... Línea 117...
113
        'first_name' => $first_name,
117
try {
114
        'last_name' => $last_name,
118
    $rsa = new rsa();
-
 
119
    $rsa->setKeys(LLWS_RSA_N, LLWS_RSA_D, LLWS_RSA_E);
115
        'image_filename' => trim(isset($data['image_filename']) ? filter_var($data['image_filename'], FILTER_SANITIZE_STRING) : ''),
120
    $data = $rsa->decrypt($data);
116
        'image_content' => trim(isset($data['image_content']) ? filter_var($data['image_content'], FILTER_SANITIZE_STRING) : '')
-
 
Línea 117... Línea 121...
117
    ];
121
} catch (Throwable $e) {
118
}
122
    echo json_encode(['success' => false, 'data' => 'ERROR_PARAMETERS3']);
-
 
123
    exit;
-
 
124
}
Línea -... Línea 125...
-
 
125
 
-
 
126
// Conversión de datos a array
119
 
127
$data = (array) json_decode($data);
120
/**
128
if (empty($data)) {
121
 * Gestiona la creación o actualización del usuario
129
    echo json_encode(['success' => false, 'data' => 'ERROR_PARAMETERS4']);
-
 
130
    exit;
-
 
131
}
-
 
132
 
Línea -... Línea 133...
-
 
133
// Extracción y validación de datos del usuario
-
 
134
$email      = trim(isset($data['email']) ? filter_var($data['email'], FILTER_SANITIZE_EMAIL) : '');
-
 
135
$first_name = trim(isset($data['first_name']) ? filter_var($data['first_name'], FILTER_SANITIZE_STRING) : '');
-
 
136
$last_name  = trim(isset($data['last_name']) ? filter_var($data['last_name'], FILTER_SANITIZE_STRING) : '');
-
 
137
 
122
 * @param array $userData Datos del usuario
138
if (!filter_var($email, FILTER_VALIDATE_EMAIL) || empty($first_name) || empty($last_name)) {
123
 * @return array|false Array con el usuario o false si hay error
139
    echo json_encode(['success' => false, 'data' => 'ERROR_PARAMETERS5']);
124
 */
140
    exit;
125
function manageUser($userData)
141
}
126
{
142
 
127
    global $DB;
143
// Búsqueda o creación de usuario
128
 
144
$user = ll_get_user_by_email($email);
129
    $user = ll_get_user_by_email($userData['email']);
145
if ($user) {
-
 
146
    $new_user = false;
-
 
147
} else {
-
 
148
    $new_user = true;
-
 
149
    $username = ll_get_username_available($first_name, $last_name);
-
 
150
    $user = ll_create_user($username, $email, $first_name, $last_name);
-
 
151
 
130
    if ($user) {
152
    // Procesamiento de imagen de perfil si se proporciona
131
        return ['user' => $user, 'is_new' => false];
-
 
132
    }
-
 
133
 
-
 
134
    $username = ll_get_username_available($userData['first_name'], $userData['last_name']);
-
 
135
    $user = ll_create_user($username, $userData['email'], $userData['first_name'], $userData['last_name']);
-
 
136
 
-
 
137
    if (!$user) {
153
    if ($user) {
138
        return ['error' => 'ERROR_MOODLE1', 'message' => 'Failed to create user'];
154
        $filename   = trim(isset($data['image_filename']) ? filter_var($data['image_filename'], FILTER_SANITIZE_EMAIL) : '');
139
    }
155
        $content    = trim(isset($data['image_content']) ? filter_var($data['image_content'], FILTER_SANITIZE_STRING) : '');
140
 
-
 
141
    if ($userData['image_filename'] && $userData['image_content']) {
-
 
142
        $tempfile = __DIR__ . DIRECTORY_SEPARATOR . $userData['image_filename'];
156
 
Línea 143... Línea -...
143
        try {
-
 
144
            file_put_contents($tempfile, base64_decode($userData['image_content']));
157
        if ($filename && $content) {
145
            if (file_exists($tempfile)) {
158
            $tempfile = __DIR__ . DIRECTORY_SEPARATOR . $filename;
146
                $usericonid = process_new_icon(context_user::instance($user->id, MUST_EXIST), 'user', 'icon', 0, $tempfile);
159
            try {
147
                if ($usericonid) {
160
                file_put_contents($filename, base64_decode($content));
148
                    $DB->set_field('user', 'picture', $usericonid, array('id' => $user->id));
-
 
149
                }
161
                if (file_exists($tempfile)) {
150
            }
-
 
Línea -... Línea 162...
-
 
162
                    $usericonid = process_new_icon(context_user::instance($user->id, MUST_EXIST), 'user', 'icon', 0, $tempfile);
-
 
163
                    if ($usericonid) {
151
        } catch (\Throwable $e) {
164
                        $DB->set_field('user', 'picture', $usericonid, array('id' => $user->id));
152
            // Log error but continue
165
                    }
Línea 153... Línea 166...
153
        } finally {
166
                }
154
            if (file_exists($tempfile)) {
167
            } catch (\Throwable $e) {
155
                unlink($tempfile);
168
            } finally {
156
            }
169
                if (file_exists($tempfile)) {
157
        }
170
                    unlink($tempfile);
158
    }
171
                }
159
 
172
            }
160
    return ['user' => $user, 'is_new' => true];
173
        }
161
}
174
    }
162
 
175
}
163
/**
176
 
164
 * Gestiona la inscripción en cursos
177
// Verificación de creación de usuario
165
 * @param object $user Usuario a inscribir
178
if (!$user) {
Línea 200... Línea 213...
200
                    }
213
                    }
201
                }
214
                }
202
            }
215
            }
203
        }
216
        }
204
    }
217
    }
205
    return true;
-
 
206
}
218
}
Línea 207... Línea -...
207
 
-
 
208
/**
219
 
209
 * Gestiona el inicio de sesión del usuario
220
// Obtención de datos completos del usuario y login
210
 * @param object $user Usuario a iniciar sesión
-
 
211
 * @return array|false Array con los datos de la sesión o false si hay error
-
 
212
 */
221
$user = get_complete_user_data('id', $user->id);
213
function manageUserSession($user)
-
 
214
{
-
 
215
    global $CFG, $SESSION;
-
 
216
 
222
if ($user) {
217
    // Cerrar sesión existente si la hay
223
    // Si hay una sesión existente, cerrarla primero
218
    if (isloggedin()) {
224
    if (isloggedin()) {
219
        require_logout();
225
        require_logout();
Línea 220... Línea 226...
220
    }
226
    }
221
 
-
 
222
    // Limpiar todas las cookies de sesión
-
 
223
    if (isset($_COOKIE)) {
-
 
224
        foreach ($_COOKIE as $name => $value) {
-
 
225
            setcookie($name, '', time() - 3600, '/');
-
 
226
            unset($_COOKIE[$name]);
-
 
227
        }
-
 
228
    }
-
 
229
 
-
 
230
    // Limpiar la cookie de Moodle específicamente
-
 
231
    set_moodle_cookie('');
227
 
232
 
228
    // Verificar si la cuenta está confirmada
-
 
229
    if (empty($user->confirmed)) {
233
    if (empty($user->confirmed)) {
230
        echo json_encode(['success' => false, 'data' => 'ACCOUNT_NOT_CONFIRMED']);
Línea -... Línea 231...
-
 
231
        exit;
234
        return ['error' => 'ACCOUNT_NOT_CONFIRMED', 'message' => 'Account not confirmed'];
232
    }
235
    }
233
 
236
 
234
    // Verificar si la contraseña ha expirado (solo para autenticación LDAP)
237
    $userauth = get_auth_plugin($user->auth);
235
    $userauth = get_auth_plugin($user->auth);
238
    if (!isguestuser() && !empty($userauth->config->expiration) && $userauth->config->expiration == 1) {
236
    if (!isguestuser() && !empty($userauth->config->expiration) && $userauth->config->expiration == 1) {
-
 
237
        $days2expire = $userauth->password_expire($user->username);
-
 
238
        if (intval($days2expire) < 0) {
-
 
239
            echo json_encode(['success' => false, 'data' => 'PASSWORD_EXPIRED']);
-
 
240
            exit;
-
 
241
        }
-
 
242
    }
-
 
243
 
-
 
244
    // Eliminar todas las cookies existentes
-
 
245
    if (isset($_SERVER['HTTP_COOKIE'])) {
-
 
246
        $cookies = explode(';', $_SERVER['HTTP_COOKIE']);
-
 
247
        foreach ($cookies as $cookie) {
-
 
248
            $parts = explode('=', $cookie);
239
        $days2expire = $userauth->password_expire($user->username);
249
            $name = trim($parts[0]);
240
        if (intval($days2expire) < 0) {
250
            setcookie($name, '', time() - 1000);
Línea -... Línea 251...
-
 
251
            setcookie($name, '', time() - 1000, '/');
241
            return ['error' => 'PASSWORD_EXPIRED', 'message' => 'Password has expired'];
252
        }
-
 
253
    }
-
 
254
 
242
        }
255
    // Completar el proceso de inicio de sesión
Línea -... Línea 256...
-
 
256
    complete_user_login($user);
243
    }
257
 
244
 
258
    // Aplicar límite de inicio de sesión concurrente
245
    complete_user_login($user);
259
    \core\session\manager::apply_concurrent_login_limit($user->id, session_id());
-
 
260
 
246
    \core\session\manager::apply_concurrent_login_limit($user->id, session_id());
261
    // Configurar cookie de nombre de usuario
247
 
262
    if (!empty($CFG->nolastloggedin)) {
248
    if (!empty($CFG->nolastloggedin)) {
263
        // No almacenar último usuario conectado en cookie
249
        // No almacenar último usuario conectado en cookie
264
    } else if (empty($CFG->rememberusername)) {
Línea -... Línea 265...
-
 
265
        // Sin cookies permanentes, eliminar la anterior si existe
250
    } else if (empty($CFG->rememberusername)) {
266
        set_moodle_cookie('');
251
        set_moodle_cookie('');
267
    } else {
-
 
268
        set_moodle_cookie($user->username);
-
 
269
    }
252
    } else {
270
 
Línea -... Línea 271...
-
 
271
    // Limpiar mensajes de error antes de la última redirección
253
        set_moodle_cookie($user->username);
272
    unset($SESSION->loginerrormsg);
254
    }
273
    unset($SESSION->logininfomsg);
Línea -... Línea 274...
-
 
274
 
255
 
275
    // Descartar loginredirect si estamos redirigiendo
-
 
276
    unset($SESSION->loginredirect);
256
    unset($SESSION->loginerrormsg);
277
 
257
    unset($SESSION->logininfomsg);
278
    // Configurar la URL de destino
258
    unset($SESSION->loginredirect);
279
    $urltogo = $CFG->wwwroot . '/my';
259
 
280
    $SESSION->wantsurl = $urltogo;
260
    $urltogo = $CFG->wwwroot . '/my';
281
 
261
    $SESSION->wantsurl = $urltogo;
282
    // Verificar que la sesión se haya iniciado correctamente
262
 
283
    if (isloggedin() && !isguestuser()) {
263
    if (isloggedin() && !isguestuser()) {
284
        // Enviar respuesta exitosa con datos del usuario
264
        return [
285
        echo json_encode([
265
            'success' => true,
286
            'success' => true,
266
            'data' => [
-
 
267
                'userid' => $user->id,
-
 
268
                'username' => $user->username,
-
 
269
                'fullname' => fullname($user),
-
 
Línea 270... Línea -...
270
                'email' => $user->email,
-
 
271
                'redirect' => $urltogo
-
 
272
            ]
287
            'data' => [
273
        ];
-
 
274
    }
-
 
275
 
-
 
276
    return ['error' => 'LOGIN_FAILED', 'message' => 'Login failed'];
-
 
277
}
-
 
278
 
288
                'userid' => $user->id,
279
// Procesamiento principal
-
 
280
$securityResult = validateSecurityParams($_REQUEST);
289
                'username' => $user->username,
281
if (isset($securityResult['error'])) {
-
 
282
    echo json_encode(['success' => false, 'data' => $securityResult['error']]);
-
 
283
    exit;
-
 
284
}
-
 
285
 
290
                'fullname' => fullname($user),
286
$dataResult = processRequestData($securityResult['data']);
291
                'email' => $user->email,
287
if (isset($dataResult['error'])) {
-
 
288
    echo json_encode(['success' => false, 'data' => $dataResult['error']]);
-
 
289
    exit;
-
 
290
}
-
 
291
 
-
 
292
$userResult = manageUser($dataResult);
-
 
293
if (isset($userResult['error'])) {
-
 
294
    echo json_encode(['success' => false, 'data' => $userResult['error']]);
292
                'redirect' => $urltogo
295
    exit;
293
            ]
296
}
-
 
297
 
294
        ]);
298
if ($userResult['is_new']) {
-
 
299
    manageCourseEnrollment($userResult['user']);
-
 
300
}
-
 
301
 
-
 
302
$user = get_complete_user_data('id', $userResult['user']->id);
-
 
303
if (!$user) {
-
 
304
    echo json_encode(['success' => false, 'data' => 'USER_NOT_FOUND']);
-
 
305
    exit;
-
 
306
}
-
 
307
 
295