[SOLUCIONADO] toba 1.5 cambio/olvido de password

Buena tarde

Agregadas primitivas para facilitar el cambio/olvido de password en la pantalla de login

Como aplicarlo, pense que era un simple tildadado, pero no lo encuentro ?

Gracias

Hola Jhon,

primeramente te comento que se agregaron 2 nuevas funciones a la clase toba_usuario llamadas, generar_clave_aleatoria y set_clave, las mismas te permiten realizar una operacion propia de cambio de clave de manera mas simple dentro de tu sistema.

La otra manera es utilizando una operacion que incluimos nosotros para manejar el caso en el cual el usuario olvida su clave y no puede loguearse. Para este caso es necesario completar una serie de pasos, primeramente tenes que configurar un smtp para que toba pueda enviar los mails de esta operacion, una vez tengas configurado esto deberias seguir los siguientes pasos.

1.- Desde toba_editor y posicionado en tu proyecto vas a utilizar el asistente para importar una operacion (imagen1).
2.- Vas a seleccionar la operacion ‘Recordatorio password’ del proyecto toba_editor (imagen2) y luego le das al boton generar.
3.- En el item de la nueva operacion vas a tildar el checkbox ‘Publica’.
4.- Deberias ir a la operacion de autenticacion de usuarios de tu proyecto y cargar un evento que sera un vinculo a la operacion importada (imagen3)
5.- Prueba el login de tu proyecto desde un browser no autenticado y verifica que aparece el boton (puedes reemplazarlo por una imagen, etc) y que cuando lo pulsas va a la operacion nueva.
6.- Como paso final hacer una exportacion del proyecto para que se persistan los cambios.

Espero que esta nueva opción te sirva ya que recuerdo nos habias pedido algo asi hace tiempo atras.
Todo feedback que nos puedas brindar es mas que bienvenido
Saludos


Retomo el tema!!!
Tengo una consulta, y es por desconocimiento…

Lo que indicaba Richard lo tengo funcionando sin problemas, excepto que logicamente, no envia los emails porque no sé como hacer lo siguiente:

primeramente tenes que configurar un smtp para que toba pueda enviar los mails de esta operacion
En este caso particular (pero no creo que haya gran diferencia), no tengo un servidor de email propio, por lo que utilizaría una cuenta especialmente abierta en un servidor de correo en web genérico. Mil gracias!!!

Hola Martin,

aca te dejo un link a la documentacion sobre como configurar un smtp para que se use desde toba.
http://repositorio.siu.edu.ar/trac/toba/wiki/Referencia/Mails

Saludos

Impecable… una más… el archivo smtp.ini, iría en la carpeta Instalacion de Toba, o puede estar contenida dentro del proyecto?
Si es así, en alguna carpeta en especial?

Ya está… va en la carpeta instalacion.

Ahora bien, todo funciona bien… pero no logro que se realice el cambio de la contraseña. El proceso lo hace bien, pero pareciera que no se logra impactar la contraseña genera en forma aleatoria en la base de datos de usuarios.

Simplemente me mantiene la anterior. Que puede estar faltandome?

Hola Martin,

mira en el metodo disparar_confirmacion_cambio de la subclase a ver si se estan recuperando exitosamente los datos de la solicitud de cambio.
Habria que agregarle un control previo y hacer terminar la ejecucion si no se recuperaron datos de una solicitud, esa es otra de las cosas a agregarle a la operacion que no debe quedar tal cual va.

La idea es que la operacion sirva como base para algo mejor. Obviamente la primer sugerencia seria que la direccion de mail no se pida por pantalla sino que se saque de datos internos del sistema, de esa forma te evitas que cualquier persona empiece a resetear claves a troche y moche con un solo mail, tenelo en cuenta esto es muy importante!!!. Se hizo asi para que se pueda probar de manera mas simple y de paso sirva a modo de ejemplo de utilizacion.

Saludos

Solucionado…

mira en el metodo disparar_confirmacion_cambio de la subclase a ver si se estan recuperando exitosamente los datos de la solicitud de cambio.
Esto llega todo impecable...
Habria que agregarle un control previo y hacer terminar la ejecucion si no se recuperaron datos de una solicitud, esa es otra de las cosas a agregarle a la operacion que no debe quedar tal cual va.
Lo hice, gracias... sino, el usuario puede hacer varios clicks solicitando el cambio de clave y tira errores y deja brechas indeseadas.
La idea es que la operacion sirva como base para algo mejor. Obviamente la primer sugerencia seria que la direccion de mail no se pida por pantalla sino que se saque de datos internos del sistema, de esa forma te evitas que cualquier persona empiece a resetear claves a troche y moche con un solo mail, tenelo en cuenta esto es muy importante!!!!. Se hizo asi para que se pueda probar de manera mas simple y de paso sirva a modo de ejemplo de utilizacion.
Totalmente de acuerdo. Se recupera el email del usuario... y además, agregué un captcha para verificar que sea casi "humano", el virus que se encuentra entre el teclado y la silla.

Para recuperar el email del usuario:


			$sql    = 'SELECT email FROM apex_usuario WHERE usuario = :usuario;';
			$se_sql = toba::instancia()->get_db()->sentencia_preparar($sql);
			$rs     = toba::instancia()->get_db()->sentencia_consultar($se_sql, array('usuario'=>$datos['usuario']));
			if (!isset($rs[0]['email'])) {
				throw new toba_error_autenticacion('El usuario no posee emails registrados en el sistema. Por favor, contáctese con un administrador, gracias.');
			} else {...

Lo que estaba fallando era que no se guardaba la clave con toba::usuario($id_usuario)->set_clave($clave_tmp);
Según vi en el código de ese método, asume que el usuario está logueado. Si es así, no se olvidó la clave!!! :slight_smile:

Para solucionar esto, creé una nueva función que reemplaza set_clave para este caso particular:


	function guarda_clave_temporal($usuario, $clave)
	{
		$clave_enc = encriptar_con_sal($clave, 'sha256');
		$sql = "UPDATE apex_usuario
					SET		clave   = :clave, autentificacion = 'sha256'
					WHERE	usuario = :usuario;";
		$id  = toba::instancia()->get_db()->sentencia_preparar($sql);
		toba::instancia()->get_db()->sentencia_ejecutar($id, array('usuario' => $usuario, 'clave' => $clave_enc));
	}

Mil gracias por las pistas, y acepto cualquier tipo de sugerencia al respecto!!!

Hola Martín, estuvimos probando todo lo que fuiste poniendo en el foro y no logramos que funcione, nos da un error (imagen 1) y en el log nos tira lo sigueinte:

exception ‘toba_error’ with message ‘Se produjo en el proceso de cambio, contactese con un administrador del sistema.’ in C:\toba_1.5.0\proyectos\control_diploma\php\recordar_password\ci_recordatorio_pwd.php:112 Stack trace: #0 C:\toba_1.5.0\proyectos\control_diploma\php\recordar_password\ci_recordatorio_pwd.php(50): ci_recordatorio_pwd->enviar_mail_aviso_cambio(Array) #1 [internal function]: ci_recordatorio_pwd->evt__formulario__enviar(Array) #2 C:\toba_1.5.0\php\nucleo\componentes\interface\toba_ci.php(321): call_user_func_array(Array, Array) #3 [internal function]: toba_ci->registrar_evento(‘formulario’, ‘enviar’, Array) #4 C:\toba_1.5.0\php\nucleo\componentes\interface\toba_ei.php(284): call_user_func_array(Array, Array) #5 C:\toba_1.5.0\php\nucleo\componentes\interface\toba_ei_formulario.php(309): toba_ei->reportar_evento(‘enviar’, Array) #6 C:\toba_1.5.0\php\nucleo\componentes\interface\toba_ci.php(201): toba_ei_formulario->disparar_eventos() #7 C:\toba_1.5.0\php\nucleo\toba_solicitud_web.php(135): toba_ci->disparar_eventos() #8 C:\toba_1.5.0\php\nucleo\toba_solicitud_web.php(55): toba_solicitud_web->procesar_eventos() #9 C:\toba_1.5.0\php\nucleo\toba_nucleo.php(60): toba_solicitud_web->procesar() #10 C:\toba_1.5.0\proyectos\control_diploma\www\aplicacion.php(25): toba_nucleo->acceso_web() #11 {main}

Te lo envío pq capáz es un problema que ya te sucedió y pudieron solucionarlo.

La configuración del smtp ya la hicimos también, pero creemos que el problema es otro.

Desde ya agradezco tu ayuda.


Mirá, la verdad… ni idea que puede ser el error.

Te cuento como tengo definida la operación (Olvido contraseña):

  • Es pública.
  • No se muestra en el menú.
  • La llamo desde un evento en la operación (Ingreso de usuarios), que lo configuré como está explicado antes por Richard.
  • Posee un CI y dentro un ei-formulario, donde muestro un ef-editable, y un ei-captcha, con un solo evento Enviar a nivel de formulario.

El código del CI, para abreviar, completo, es el siguiente:


<?php
class ci_olvido_clave extends toba_ci
{
	protected $usuario;
	protected $randr;
	private   $error_cambio = 'Se produjo un error en el proceso de cambio de contraseña. Por favor, contáctese con un administrador del sistema, gracias.';
	
	function ini()
	{
		//Preguntar en toba::memoria si vienen los parametros
		$this->usuario = toba::memoria()->get_parametro('usuario');
		$this->randr   = toba::memoria()->get_parametro('randr');		//Esto hara las veces de unique para la renovacion

		//Esto es por si se trata de entrar al item directamente
		$item = toba::memoria()->get_item_solicitado();
		$tms = toba_manejador_sesiones::instancia();
		if ($item[0] == 'toba_editor' && !$tms->existe_usuario_activo()) {
			throw new toba_error_ini_sesion('No se puede correr este item fuera del editor');
		}
	}

	//-----------------------------------------------------------------------------------
	//---- Configuraciones --------------------------------------------------------------
	//-----------------------------------------------------------------------------------

	function conf__pant_inicial(toba_ei_pantalla $pantalla)
	{
		//Si viene con el random seteado es que esta confirmando el cambio de contraseña
		if (isset($this->randr)) {
			$pantalla->eliminar_dep('formulario');
			$pantalla->set_descripcion('La nueva contraseña fue enviada a su cuenta de email. Por favor, verifíquela', 'info');
			$this->disparar_confirmacion_cambio();
			toba::notificacion()->agregar('La nueva contraseña fue enviada a su cuenta de email. Por favor, verifíquela', 'info');
		}
	}

	//-----------------------------------------------------------------------------------
	//---- formulario -------------------------------------------------------------------
	//-----------------------------------------------------------------------------------

	function conf__formulario(toba_ei_formulario $form)
	{
		//Probablemente esto vaya vacio a excepcion del usuario si es que se pasa
		if (isset($this->usuario) && (!is_null($this->usuario))) {
			$form->set_datos_defecto(array('usuario' => $this->usuario));
			$form->set_solo_lectura(array('usuario'));
		}
		//configuro la imagen de verificacion
		$path = toba::proyecto()->get_www();
		$parametros = array('image_type'   => 1,
							'image_width'  => 200,
							'image_bg_color' => '#FFCCFF',
							'line_color' => '#FF33FF',
							'arc_line_colors' => '#660000',
							'use_gd_font'  => true,
							'gd_font_file' => $path['path'].'/gdfonts/bubblebath.gdf');
		$form->ef('es_humano')->set_longitud_codigo(6);
		$form->ef('es_humano')->set_parametros_captcha($parametros);
	}

	//----------------------------------------------------------------------------------------
	//-------- Envio del email de solicitud de cambio ----------------------------------------
	//----------------------------------------------------------------------------------------
	function evt__formulario__enviar($datos)
	{
		//verifico que se haya ingresado el codigo de verificacion
		if (!$datos['es_humano']) {
			throw new toba_error('El código de verificación ingresado no es correcto. Inténtelo nuevamente.');
		}
		//verifico que vengan los datos que necesito
		if (! isset($datos['usuario'])) {
			throw new toba_error_autenticacion('No se suministro un usuario válido');
		}
		//Si el usuario existe, entonces disparo el envio de mail 
 		if (!$this->verificar_usuario_activo($datos['usuario'])) {
			throw new toba_error_autenticacion('No se suministro un usuario válido');
		} else {
			//recupero el email del usuario, registrado en el sistema de usuarios
			$sql    = 'SELECT email FROM apex_usuario WHERE usuario = :usuario;';
			$se_sql = toba::instancia()->get_db()->sentencia_preparar($sql);
			$rs     = toba::instancia()->get_db()->sentencia_consultar($se_sql, array('usuario'=>$datos['usuario']));
			if (!isset($rs[0]['email'])) {
				throw new toba_error_autenticacion('El usuario no posee emails registrados en el sistema. Por favor, contáctese con un administrador, gracias.');
			} else {
				$datos['email'] = $rs[0]['email'];
				$this->enviar_mail_aviso_cambio($datos);
				$this->pantalla()->set_descripcion('Se ha enviado un mail a la cuenta especificada. Por favor, verifíquela.
');
				$this->pantalla()->eliminar_dep('formulario');
			}
		}
	}

	function verificar_usuario_activo($usuario)
	{
		try {
		    toba_usuario::es_usuario_bloqueado($usuario);		//Tengo que verificar que el usuario exista
		} catch (toba_error_db $e) {							//Ni true ni false... no existe el usuario.
		    return false;
		}
		return true;
	}

	//Envio un primer mail con un link para confirmar el cambio, si no lo usa... fue
	function enviar_mail_aviso_cambio($datos)
	{
		//Genero un pseudorandom unico... 
		$tmp_rand = $this->get_random_temporal();
		//Genero el link para el mail
		$vinculos = $this->generar_link_confirmacion($datos['usuario'], $tmp_rand);	
		//Se envia el mail a la direccion especificada por el usuario.
	    $asunto   = 'Solicitud de cambio de contraseña';
		$cuerpo_mail =	'<p>Este mail fue enviado a esta cuenta porque se <strong>solicito un cambio de contraseña</strong>.'
						.'Si usted solicito dicho cambio haga click en el siguiente enlace para confirmarlo:
'
						.$vinculos['click'].'
 El mismo será válido unicamente por 24hs.

'
						.'Si tiene problemas para conectarse al mismo, copie la siguiente dirección en la ventana de su navegador preferido:
'
						.$vinculos['enlace'].'</p>';
		//Guardo el random asociado al usuario y envio el mail
		toba::instancia()->get_db()->abrir_transaccion();
		try {
			$this->guardar_datos_solicitud_cambio($datos['usuario'], $tmp_rand, $datos['email']);
			toba::instancia()->get_db()->cerrar_transaccion();
			$mail = new toba_mail($datos['email'], $asunto, $cuerpo_mail);
			$mail->set_html(true);
			$mail->enviar();
		} catch (toba_error $e) {
			toba::instancia()->get_db()->abortar_transaccion();
			throw new toba_error($this->error_cambio);
		}
	}

	function get_random_temporal()
	{
		$uuid = uniqid(rand(), true);
		$rnd  = sha1(microtime().$uuid.rand());
		return $rnd;
	}

	function generar_link_confirmacion($usuario, $random)
	{
		$path            = toba::proyecto()->get_www();
	    $opciones        = array('param_html' => array('tipo' => 'normal' , 'texto' => 'Cliquee aquí'), 'prefijo' => 'http://'.$_SERVER['SERVER_NAME'].$path['url']);
	    $opciones_enlace = array('prefijo' => 'http://'.$_SERVER['SERVER_NAME'].$path['url']);
	    $parametros      = array('usuario' => $usuario, 'randr' => $random);
	    $vinculos        = array('click'  => toba::vinculador()->get_url(null, null, $parametros, $opciones),
								 'enlace' => toba::vinculador()->get_url(null, null, $parametros, $opciones_enlace));
		return $vinculos;
	}

	function guardar_datos_solicitud_cambio($usuario, $random, $mail)
	{
		$sql    = 'UPDATE apex_usuario_pwd_reset SET bloqueado = 1 WHERE usuario = :usuario;';
		$up_sql = toba::instancia()->get_db()->sentencia_preparar($sql);
		$rs     = toba::instancia()->get_db()->sentencia_ejecutar($up_sql, array('usuario'=>$usuario));
		$sql    = 'INSERT INTO apex_usuario_pwd_reset (usuario, random, email) VALUES (:usuario, :random, :mail);';
		$in_sql = toba::instancia()->get_db()->sentencia_preparar($sql);
		$rs     = toba::instancia()->get_db()->sentencia_ejecutar($in_sql, array('usuario'=>$usuario, 'random' => $random, 'mail' => $mail));
	}
	
	//----------------------------------------------------------------------------------------
	//-------- Envio del email con la clave temporal -----------------------------------------
	//----------------------------------------------------------------------------------------
	function disparar_confirmacion_cambio()
	{
	    //Aca tengo que generar una clave temporal y enviarsela para que confirme el cambio e ingrese con ella.
	    $clave_tmp  = toba_usuario::generar_clave_aleatoria('8');
	    //Recupero mail del usuario junto con el hash de confirmacion
	    $datos      = $this->recuperar_datos_solicitud_cambio($this->usuario, $this->randr);
		if (!isset($datos) || empty($datos)) {
			throw new toba_error($this->error_cambio);
		}
		//Armo el mail nuevo
	    $asunto     = 'Nueva contraseña';
	    $cuerpo_mail = '<p>Se ha recibido su confirmación exitosamente, su contraseña fue cambiada a: 
'
						.$clave_tmp
						.'
 Por favor, en cuanto pueda cambiela por una contraseña personalizada.
'
						.'Esto puede realizarse ingresando al sistema, en el menú Configuración, opción Cambio de contraseña.
'
						.'Muchas gracias.</p>';
		//Cambio la clave del usuario, envio el nuevo mail y bloqueo el random
 		toba::instancia()->get_db()->abrir_transaccion();
		try {
			//Seteo la clave para el usuario
			$this->guarda_clave_temporal($this->usuario, $clave_tmp);
			//Bloqueo el pedido para que no pueda ser reutilizado
			$this->bloquear_random_utilizado($this->usuario, $this->randr);
			toba::instancia()->get_db()->cerrar_transaccion();
			//Enviar nuevo mail con la clave temporaria
 			$mail = new toba_mail($datos[0]['email'], $asunto, $cuerpo_mail);
			$mail->set_html(true);
			$mail->enviar();
		} catch (toba_error $e) {
			toba::instancia()->get_db()->abortar_transaccion();
			throw new toba_error($this->error_cambio);
		}
 	}

	function recuperar_datos_solicitud_cambio($usuario, $random)
	{
		$sql = "SELECT  usuario, email
					FROM apex_usuario_pwd_reset
					WHERE	usuario   = :usuario
					AND 	random    = :random
					AND 	age(now(), validez) < interval '1 day'
					AND 	bloqueado = 0;";
		$id  = toba::instancia()->get_db()->sentencia_preparar($sql);
		$rs  = toba::instancia()->get_db()->sentencia_consultar($id, array('usuario'=>$usuario, 'random' => $random));
		return $rs;
	}

	function guarda_clave_temporal($usuario, $clave)
	{
		$clave_enc = encriptar_con_sal($clave, 'sha256');
		$sql = "UPDATE apex_usuario
					SET		clave   = :clave, autentificacion = 'sha256'
					WHERE	usuario = :usuario;";
		$id  = toba::instancia()->get_db()->sentencia_preparar($sql);
		toba::instancia()->get_db()->sentencia_ejecutar($id, array('usuario' => $usuario, 'clave' => $clave_enc));
	}
	
	function bloquear_random_utilizado($usuario, $random)
	{
		$sql = 'UPDATE apex_usuario_pwd_reset SET bloqueado = 1
					WHERE usuario = :usuario
					AND   random  = :random';
		$id  = toba::instancia()->get_db()->sentencia_preparar($sql);
		$rs  = toba::instancia()->get_db()->sentencia_ejecutar($id, array('usuario'=>$usuario, 'random' => $random));
	}
}
?>

Ojo, copie el font del captcha al directorio navegable del proyecto: www/gdfonts/…

El smtp.ini lo copie en la carpeta toba_1_x\instalaciones, y lo configuré para pruebas con el smtp de mi propia cuenta de email… te adjunto el código genérico a poner dentro (hay que sacarle los ; y si alguno de los parámetros no va, dejalo comentado y listo):


; [smtp_telefonica]		//Nombre de la configuracion smtp
; host=127.0.0.174		//IP o Nombre de Red del servidor SMTP
; seguridad=ssl|tls|		//Determina si se usa conexion segura en la comunicacion con el servidor
; auth=0|1 			//Determina si el servidor SMTP requiere autenticacion
; usuario=usuario			//Nombre de usuario autenticado
; clave=usuario			//Clave del usuario autenticado
; puerto=25			//Puerto en que se encuentra escuchando el servidor SMTP
; from=default@miservidor.com	//Direccion de correo saliente por defecto

Espero que te sirva, y apreciaria cualquier corrección que pudiera tener el código!
Saludos y suerte!

Hola Gente,

@Martin:
Subi una version nueva de la clase que maneja la operacion de modificacion de pwd, la misma corrige el bug que mencionabas y uno extra que encontre y tenia el mismo modus operandi, por lo tanto te pido mires los cambios asi los podes pasar a tu subclase. El error era que al solicitar la llamada a toba::usuario() se estaba devolviendo una instancia de la clase toba_usuario_no_autenticado… la cual ignora completamente el id pasado como parametro al constructor de ahi el problema que te encontraste, gracias por el aviso :).

@Alejandro:
El error lo puede disparar tanto el envio del mail como tambien el metodo ‘guardar_datos_solicitud_cambio’ que realiza un par de SQL para guardar la solicitud de cambio de pwd.
Para saber puntualmente cual es el inconveniente, podes mirar en el log de toba, alli se esta guardando el mensaje especifico del error que se genero.

Saludos

Impecable… gracias!!!

Hola a todos! Primero que nada agradecerle a Martin por su ayuda y segundo para contarles que el problema (creemos nosotros) es que cuando creamos el archivo smtp.ini lo definimos [smtp_rectorado], lo cual nos daba el error, una vez que cambiamos el nombre del archivo a smtp funcionó correctamente.
Aclaro que además se había agregado al archivo instalacion.ini la siguiente línea:
smtp=smtp_rectorado
Es por esto que pensamos que el error era causado por este motivo.

Muchas gracias.

Si, los archivos ini son medio venenosos con el tema de caracteres, no se si habria funcionado para el caso de nombre de seccion pero segun la ayuda habria que rodear los valores entre comillas dobles.
Aca les dejo la ayuda de PHP al respecto para que tengan en cuenta por si necesitan hacer archivos ini de esta manera, yo de paso aprendi como mandar valores null xD.


Note: If a value in the ini file contains any non-alphanumeric characters it needs to be enclosed in double-quotes ("). 

Note:  There are reserved words which must not be used as keys for ini files. These include: null, yes, no, true, and false. Values null, no and false results in "", yes and true results in "1". 
        Characters {}|&~![()" must not be used anywhere in the key and have a special meaning in the value. 

Saludos

Retomando: tengo un archivo smtp.ini en …/instalacion/smtp.ini

[smtp_ucm]
host=smtp.gmail.com
auth=1
usuario=jorozco
clave=10266548
puerto=465
seguridad=

y en instalacion.ini agrego la linea
smtp=smtp_ucm

No me funciona el mail;
Mi pregunta concreta es el USUARIO Y LA CLAVE, tienen que ser obligadamente del Administrador del servidor ?, porque estoy tratando con el usuario y la clave de mi correo y me responde el log:
[DEBUG][cna] Proceso de envio de random a cuenta: No existe la entrada ‘smtp_ucm’ el archivo ‘/proyectos/toba_2_0/instalacion/smtp.ini’

Gracias

Hola, fijate que para gmail, el parámetro seguridad tiene que ser igual a SSL.
Se me ocurre que ahí puede estar el error.
Saludos!

Hola Jhon,

El problema es que no esta parseando correctamente el formato del archivo ini, puede ser por varios motivos, incluso el fin de linea en algunos casos. Si puedes verifica que no quedo algun caracter extraño (no visible) que este rompiendo el formato.

De todas maneras como te dijo Martin, el parametro seguridad deberia ir en SSL para gmail.

Saludos

Gracias, Martín y Richard; efectivamente en el .ini, estaban quedando espacios después del final.