May 10

Introducción.

La situación es la siguiente, se cuenta con un CMS desarrollado en PHP bajo el framework de CodeIgniter con su propio sistema de autenticación en el que se almacenan los usuarios de la siguiente manera.

CREATE TABLE IF NOT EXISTS `core_usuario` (
`id_usuario` int(11) unsigned NOT NULL auto_increment,
`estado` enum(‘activo’,'inactivo’) NOT NULL,
`_username` varbinary(16) NOT NULL,
`_password` varbinary(32) NOT NULL,
`nombres` varchar(50) NOT NULL,
`apellidos` varchar(50) NOT NULL,
`fecha_nacimiento` date default NULL,
`tipo_documento` enum(‘cc’,'ce’,'ti’,'nit’) NOT NULL,
`documento_identidad` varchar(12) NOT NULL,
`genero` enum(‘m’,'f’) NOT NULL,
`correo` varchar(255) NOT NULL,
`pagina` varchar(255) default NULL,
`observaciones` varchar(255) default NULL,
`fecha_creacion` datetime NOT NULL,
`fecha_actualizacion` datetime NOT NULL,
PRIMARY KEY  (`id_usuario`),
);

En el sitio se ha instalado un foro basado en la versión 1.1.11 de Simple Machines el cual comparte la base de datos con el CMS.  Se necesita encontrar la forma de unificar los nombres de los usuarios y las contraseñas para tener una única identificación para la autenticación en los dos sistemas.

Para hacer esto se utiliza el API de SSI de SMF de la siguiente manera.

Hooks de integración.

SMF provee una facilidad para alterar el ciclo de flujo del software mediante la manipulación de hooks que se agregan a etapas específicas del programa para modificar su comportamiento por defecto.  En este caso nos interesa crear un hook sobre el punto integrate_validate_login ya que ese es el punto exacto en que SMF va a realizar la validación de los usuarios durante su autenticación.

Para implementar esto se crea un archivo llamado jimhook.php (el nombre es arbitrario) con el siguiente contenido inicial.

<?php
define('SMF_INTEGRATION_SETTINGS', serialize(array(
    'integrate_validate_login' => 'user_validate',
)));

require_once('SSI.php');

function user_validate()
{
    // Implementación de la lógica de la nueva autenticación.
}
?>

Estos hooks deben asociarse al sistema de foros agregando la siguiente línea al inicio del archivo index.php.

include_once("jimhook.php");

Conexión a la base de datos.

Como se mencionó inicialmente el CMS fue desarrollado en CodeIngniter y en este caso, comparte la base de datos con los foros.  El primer paso es obtener la información de conexión a la base de datos desde los archivos de configuración del CMS.

define('BASEPATH', 1);
include('../pt/system/application/config/database.php');

Teniendo esta información se realiza una conexión global a la base de datos utilizando las funciones de PDO.

$pdo = null;

try
{
    $pdo = new PDO("mysql:host={$db['default']['hostname']};dbname={$db['default']['database']}",
                   $db['default']['username'],
                   $db['default']['password'],
                   array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8")
    );
}
catch (PDOException $e)
{
    print "Error!: " . $e -> getMessage() . "<br/>";
    die();
}

Funciones de apoyo del CMS.

Se crean algunas funciones básicas que servirán de soporte para el nuevo procedimiento de autenticación.

function existeUsuarioEnPlataforma($usuario)
{
    global $pdo;

    $stmt = $pdo -> prepare("SELECT id_usuario FROM `usuarios` WHERE user=?");

    $results = $stmt -> execute(array($usuario));

    return ($stmt -> rowCount() > 0);
}

Verifica si el usuario identificado por el nombre de usuario ($usuario) existe o no registrado en el CMS.  Retorna true o false según se encuentren o no efectivamente registrados.

function autenticarUsuarioEnPlataforma($usuario, $contrasena)
{
    global $pdo;

    $stmt = $pdo -> prepare("SELECT id_usuario FROM `usuarios` WHERE user=? AND pass=?");

    $results = $stmt -> execute(array($usuario, MD5($contrasena)));

    return ($stmt -> rowCount() > 0);
}

Verifica que el usuario identificado con el nombre de usuario ($usuario) tenga efectivamente a $contraseña como clave de usuario.  Retorna true en caso de coincidir, false de lo contrario.

Nótese como el CMS almacena sus contraseñas en MD5 motivo por el cual es necesario realizar esta conversión antes de realizar la comparación en la consulta SQL.

Funciones de apoyo de los foros.

De manera análoga, estas funciones facilitan la manipulación de la información en las tablas del sistema de foros, las cuales tienen configurado el prefijo foros_ en sus tablas.

function existeUsuarioEnForos($usuario)
{
    global $pdo;

    $stmt = $pdo -> prepare("SELECT ID_MEMBER FROM foros_members WHERE memberName = ?");

    $results = $stmt -> execute(array($usuario));

    if($stmt -> rowCount() == 0)
        return false;

    $fuente = $stmt -> fetch();

    return $fuente['ID_MEMBER'];
}

Verifica si el usuario identificado por el nombre de usuario ($usuario) existe o no registrado en el foro .  Retorna el identificador del usuario si existe o false de lo contrario.

function traerUsuario($usuario, $contrasena)
{
    global $pdo, $sourcedir, $modSettings;

    if(!existeUsuarioEnPlataforma($usuario))
        return false;

    $stmt = $pdo -> prepare("SELECT * FROM `usuarios` WHERE user=?");

    $results = $stmt -> execute(array($usuario));

    $fuente = $stmt -> fetch();

    require_once($sourcedir . '/Subs-Members.php');

    $regOptions = array('username' => $fuente['user'],
                        'password' => $contrasena,
                        'password_check' => $contrasena,
                        'email' => $fuente['email'],
                        'posts' => '0',
                        'ID_GROUP' => '0',
                        'ID_POST_GROUP' => '4');

    $memberID = registerMember($regOptions);

    return ($memberID > 0);
}

Obtiene la información del usuario de plataforma identificado por $usuario y $contrasena, y lo agrega en la base de datos del foro a través de su API interno.  A este nivel no se realiza ninguna verificación de autenticación.

function activarUsuarioForo($usuario, $estado='1')
{
    global $pdo;

    $stmt = $pdo -> prepare("UPDATE foros_members SET is_activated = ? WHERE memberName = ?");

    $control = $stmt -> execute(array($estado, $usuario));

    return $control;
}

Activa al usuario del foro recién creado, el cual por defecto siempre queda en espera de confirmación (is_activated = 3).

function actualizarContrasenaForo($usuario, $contrasena)
{
    global $pdo;

    $passwd       = sha1(strtolower($usuario) . $contrasena);
    $passwordSalt = substr(md5(mt_rand()), 0, 4);

    $stmt = $pdo -> prepare("UPDATE foros_members SET passwd = ?, passwordSalt = ? WHERE memberName = ?");

    $control = $stmt -> execute(array($passwd, $passwordSalt, $usuario));

    return $control;
}

Actualiza la $contrasena del $usuario en el sistema de foros.  Nótese como la $contrasena se recibe de manera plana y se almacena en la base de datos de SMF en SHA1.

Acerca del comportamiento del login de SMF.

Algo que se debe tener en cuenta acerca del comportamiento del login de SMF es que desde el cliente (navegador del usuario) se envía la contraseña ya en su propia representación SHA1 así que si la contraseña con que se va a comparar no está en la misma representación, como en este caso, el CMS la almacena en MD5, se tiene entonces un problema.

Para solventar esto, el sistema de foros permite solicitar nuevamente la contraseña al usuario (retry) y en este segundo intento la envía totalmente plana para su manipulación libre.  En este punto es donde la aprovechamos para verificar la autenticación del usuario contra la información del CMS, crear el usuario en el foro si no existe y actualizar la contraseña en el foro previniendo que haya sido actualizada antes en el CMS.

Implementación del nuevo proceso de autenticación.

function user_validate()
{
    $user = $_REQUEST['user'];
    $id   = 0;

    // Verificar un usuario proveniente de plataforma.

    if(existeUsuarioEnPlataforma($user))
    {
        $id = existeUsuarioEnForos($user);

        // Nueva lógica de autenticación.
    }

    // El usuario no existe en plataforma, verificar los nativos del foro.

    return false;
}

La base de la nueva autenticación es entonces la definición de la función user_validate que corresponde con la especificada inicialmente durante la configuración de los hooks.

En ella se verifica inicialmente si el usuario que intenta acceder al sistema (login) se encuentra presente o no en la base de datos de usuarios del CMS.  En caso de no estar presente el control de la autenticación se libera para que el sistema verifique sus usuarios propios, esto permite definir también usuarios internos del foro que no estén presentes en el CMS.

El paso siguiente consiste en determinar si el usuario existe previamente o no en el foro, es decir, no es su primer ingreso al mismo.  A partir de esta respuesta se toma uno de los siguientes caminos.

  • Si no está disponible la contraseña plana (primer login) se solicita nuevamente (segundo login).
  • Si el usuario no existe en el foro entonces ...
    • Se verifica que el nombre de usuario y la contraseña coincidan.
    • Se crea el usuario en el foro.
    • Se activa al nuevo usuario.
  • Si el usuario ya existía previamente en el foro entonces ...
    • Se verifica que el nombre de usuario y la contraseña coincidan.
    • Se actualiza la contraseña en el foro por si ha sido actualizada previamente en el CMS.

La implementación de estas acciones se detalla a continuación.  En el caso en que el usuario no exista previamente en el foro se ejecuta la siguiente lógica del negocio.

if($id === false)
{
    // Esta disponible la contrasena (2do. login).

    if(isset($_REQUEST['passwrd']) && !empty($_REQUEST['passwrd']))
    {
        $auth = autenticarUsuarioEnPlataforma($user, $_REQUEST['passwrd']);

        if($auth)                           // La informacion del usuario es valida.
        {
            $id = traerUsuario($user, $_REQUEST['passwrd']);

            activarUsuarioForo($user);

            return false;                   // La autenticacion tiene EXITO.
        }
        else                                // La informacion del usuario NO es valida.
            return true;                    // La autenticacion FALLA.
    }
    else                                    // No esta disponible la contrasena (1er. login).
        return "retry";                     // Vuelva a solicitar el login para confirmar.
}

En el caso en que el usuario si exista previamente en el foro, el procedimiento es mas simple y se ejecuta la siguiente lógica del negocio.

// El usuario existe en el foro.

if($id !== false)
{
    // Esta disponible la contrasena (2do. login) -> actualizar la contraseña en el foro.

    if(isset($_REQUEST['passwrd']) && !empty($_REQUEST['passwrd']))
    {
        $auth = autenticarUsuarioEnPlataforma($user, $_REQUEST['passwrd']);

        if($auth)                           // La informacion del usuario es valida.
        {
            actualizarContrasenaForo($user, $_REQUEST['passwrd']);

            return false;                   // La autenticacion tiene EXITO.
        }
        else                                // La informacion del usuario NO es valida.
            return true;                    // La autenticacion FALLA.
    }
    else                                    // No esta disponible la contrasena (1er. login).
        return "retry";                     // Vuelva a solicitar el login para confirmar.
}

Conclusiones.

Hasta ahora, con poca experiencia en su uso, SMF parece ser un sistema de foros útil y práctico.  El proceso de determinar esta unificación de la autenticación fue largo y doloroso debido a la poca documentación que pude encontrar acerca del API, la cual en su mayor parte se encuentra diseminada en los foros de su sitio web.

En términos de su código parece tener un nivel decente de flexibilidad, el concepto de hooks permite realizar modificaciones interesantes al flujo normal del software, sin embargo es difícil formalizarlo al no contar con información suficiente de su lógica de funcionamiento.  Algunas partes del software, en especial los temas, adolecen de separación MVC por lo que se hace necesario editar funciones, entre comillas, que retornan el código HTML que se desea modificar siendo esto molesto, difícil y propenso a errores, sobretodo si se compara con tener archivos PHP separados con la lógica y HTML con la presentación como sería una mejor opción.

Finalmente, después de varios días de luchas y de pruebas, la unificación de la autenticación está funcionando y se ve bien, de todas maneras es mi primer acercamiento a este software por lo que no puedo garantizar que sea la mejor aproximación.  Como siempre, estoy abierto a sugerencias constructivas.

Enlaces.

Tagged with:



En May 10 de 2010, Jorge Iván Meza Martínez escribió acerca de Integración de una autenticación externa con los foros de Simple Machines 1.1.11.
May 10

Existen gran cantidad de formas de descargar videos de YouTube, entre ellas miles de sitios web, aplicaciones y demas, pero exsiste un paquete en Ubuntu de una aplicacion facil de instalar que permite desde consola descargar los videos en alta calidad y utilizando el nombre del video como nombre del archivo.

Instalación :

  • Abrir una consola
  • Actualizar los paquetes por si las moscas
    sudo apt-get update
  • Instalar el Youtube Downloader
    sudo apt-get install youtube-dl

Uso :

  • Vaya a Youtube
  • Seleccione el video a descargar
  • Copie la URL de la pagina del video
  • Abra una consola
  • Ejecute la aplicacion para descargar el video
    youtube-dl -t -b http://www.youtube.com/watch?v=iy4o8KBvvwE
  • Este descarga el video a la mayor calidad posible y coloca el titulo del video como nombre del archivo

Opciones :

  • -t : Colocarle el titulo del archivo como nombre del archivo
  • -b : Bajar el video en la mejor calidad posible
  • -c : Continuar la descarga de un video
  • -m : Version para moviles
  • y un monton mas ...
Tagged with:



En May 10 de 2010, Marlon J. Manrique escribió acerca de Descargar Video de YouTube desde Ubuntu 10.04.
May 10

Desde hace ya algunas semanas la version de UBuntu 10.04 vio la luz, pocos dias despues estaba actualizando todos mis sistemas a esta nueva version la cual me tiene muy satisfecho sobre todo con la rapidez con que enciende y apaga el equipo en menos de 30 segundos, una velocidad asombrosa para los que estabamos acostumbrados de ver como el sistema cargaba cada uno de los pasos en la pantalla de inicio.

Esta vez al Dell Mini 9 que tiene un procesador Atom N270 de dos núcleos, disco duro de estado solido de 30 GB y memoria de 2 GB le instale la versión Notebook antes llamada Remix de Ubuntu, la cual es ideal para este tipo de notebooks la cual permite sacarle el mayor espacio a la pantalla gracias a que maximiza las ventana y las adhiere al espacio del menu en la barra superior.

Para la instalación descargue el ISO via torrent del sitio oficial de Ubuntu y luego cree un disco de inicio con una memoria USB y la aplicacion "Start Up Disk Creator" utilizando mi computadora portatil que en ese momento tenia Ubuntu 9.10, luego fue simplemente seguir los pasos del instalador e instalar el sistema.

Drivers :

  • La mayoria de drivers para el hardware es reconocido e instalado por Ubuntu menos el driver de la tarjeta de red inalambrica que se debe instalar luego reiniciando el equipo, conectando a la red por medio de cable y ejecutando "Hardware Drivers" el cual permite instalar el driver Broadcom STA wireless.
  • Si no se tiene conexion de red es posible instalar el driver desde la memoria USB de inicio como lo describe Jorge Ivan Meza en su Blog : Activar las tarjetas WiFi Broadcom después de instalar Linux Ubuntu 10.04

Hasta Ahora :

  • Me hace falta el efecto de zoom de Compiz el cual tratare de actualizar
  • Reproduce muy bien video :)
  • Me ha funcionado muy bien para la conferencias
  • Me gusta mucho esta nueva version del Notebook
  • No he probado todas las cosas que quiero probar

Problemas :

  • Las aplicaciones Java al momento de maximizarse aparecen en blanco por lo cual se debe redimensionar la ventana para que aparezca el contenido, esto usando la version 6 Update 20 del JDK (sun-java6-jdk)
Tagged with:



En May 10 de 2010, Marlon J. Manrique escribió acerca de Instalando Ubuntu 10.04 Notebook en Dell Mini 9.
May 10

Hace poco leyendo en un blog me encontre con un Plugin muy interesante para Firefox el cual convierte la ventana de Descarga de Firefox en un Tab dentro del navegador permitiendo de una forma mas facil hacer el seguimiento de las descargas y en caso de estos computadores pequeños, los notebooks como el Dell Mini 9 no adicionar otra ventana mas al escritorio (por eso me gusto tanto)

El plugin permite tambien personalizar la visualizacion presentada y el comportamiento del tab que es visualizado cuando se descarga algun software.

Enlace :

Tagged with:



En May 10 de 2010, Marlon J. Manrique escribió acerca de Quitar Ventana de Descargas en Firefox.
May 10

Hace ya algún tiempo no hacia algo de desarrollo para Mobile Processing (de todas formas en este tiempo en la Universidad he dado algunos mini cursos y también algunas conferencias), algunas de las librerías ya están lo suficientemente maduras y no por motivos de tiempo no había podido pensar en otras cosas para adicionar hasta el viernes que me dispuse a leer sobre la versión para Android de Processing (pronto estare hablando de este proyecto), principal competencia ahora de Mobile Processing y que pronto se convertirá en el estandard para móviles abriendo las puertas del mausoleo para Mobile Processing.

En la pagina de Processing para Android, en la parte de instalación se debe descargar una versión especial de Processing que trae el modo Android para el desarrollo de aplicaciones móviles y que para que todo funcione debe descargarse el SDK de Android, pero que este en un futuro sera adicionado a la distribución evitando la necesidad de descargar el software esto siguiendo los lineamientos de Processing de mantener la herramienta simple y fácil de usar. Recorde que ese mismo dia me habia contado un estudiante que habia tenido problemas con la instalacion del ambiente en Windows y que tambien he sido victima de la instalacion dispendiosa de los requerimientos del mismo.

Mobile Processing esta basado en el ambiente de desarrollo de Processing el cual esta desarrollado bajo Java y utiliza Jikes como compilador Java, de tal modo que utiliza el JRE solo para la ejecucion del editor, la version Mobile adiciona la necesidad de un ambiente de desarrollo para J2ME lo cual cubria el Wireless Toolkit que necesitaba de un JDK; sumando todo esto para instalar el ambiente de desarrollo se necesitaba instalar un JDK y el WTK y luego expandir el archivo de Mobile, ejecutar y configurar el ambiente de desarrollo para utilizar el WTK.

La idea era crear una distribucion que al igual que Processing la cual solo fuera expandir y ejecutar, para esto se utilizo de base el directorio de Mobile Processing al cual se le adiciono el directorio java, donde se instalo el JDK 6 Update 20, ademas de instalar en el directorio wtk la version 2.5.2 del Wireless Toolkit el cual debio ser modificado para que utilizara la version de java instalada anteriormente, adicionamente se modifico el codigo del llamado al verificar y emulador utilizado en Mobile para que tomara el WTK instalado desde la primera ejecucion del ambiente, estos pasos fueron relativamente faciles y se crearon las versiones para Windows y Linux de 32 bits, las cuales se probaron satisfactoriamente en maquinas virtuales sin software pre instalado de Windows XP, Windows 7 y Ubuntu 10.04 con esto se crearon las distribuciones respectivas las cuales tenian un tamaño de 109 MB, pero teniendo en cuenta que en Google Code el maximo de tamaño permitido por archivo es de 100 MB se procedio a quitar documentacion y ejemplos del WTK y el JDK llegando a un tamaño de 78 MB.

Demasiadas explicaciones, pero es mejor documentar todo el proceso, :)
Para los que estaban esperando ansiosos los links de descarga aqui estan :

Descarga :

Enlaces :

Tagged with:



En May 10 de 2010, Marlon J. Manrique escribió acerca de Mobile Processing, Expandir y Ejecutar.