Proyectos de Subversion Moodle

Rev

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

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