<?xml version="1.0" encoding="UTF-8"?>
<!-- EN-Revision: 15103 -->
<!-- Reviewed: no -->
<sect1 id="zend.auth.adapter.dbtable">
    <title>Tabla de base de datos de autenticación</title>
    <sect2 id="zend.auth.adapter.dbtable.introduction">
        <title>Introducción</title>
        <para>
            <classname>Zend_Auth_Adapter_DbTable</classname> proporciona la capacidad
            de autenticar contra credenciales almacenadas en una tabla de la base de
            datos. Como <classname>Zend_Auth_Adapter_DbTable</classname> requiere una 
            instancia de <classname>Zend_Db_Adapter_Abstract</classname> que será
            pasada a su constructor, cada instancia está vinculada a una conexión
            concreta de la base de datos. Se pueden establecer otras opciones de 
            configuración a través del constructor y de métodos de instancia:
        </para>
        <para>
            Las opciones de configuración disponibles incluyen:
            <itemizedlist>
                <listitem>
                    <para>
                        <methodname>tableName</methodname>: Nombre de tabla de la base de datos que
                        contiene las credenciales de autenticación, y contra la cual
                        se realiza la búsqueda de autenticación en la base de datos.
                        </para>
                </listitem>
                <listitem>
                    <para>
                        <methodname>identityColumn</methodname>: Nombre de la columna de la tabla
                        de la base de datos utilizada para representar la identidad. La 
                        columna identidad debe contar con valores únicos, tales como un
                        apellido ó una dirección de e-mail.
                    </para>
                </listitem>
                <listitem>
                    <para>
                        <methodname>credentialColumn</methodname>: Nombre de la columna de la tabla 
                        de la base de datos utilizada para representar la credencial.
                        Conforme a un sistema de identidad simple y autenticación de 
                        contraseña, el valor de la credencial corresponde con la 
                        contraseña. Véase también la opción <methodname>credentialTreatment
                        </methodname>.
                    </para>
                </listitem>
                <listitem>
                    <para>
                        <methodname>credentialTreatment</methodname>: En muchos casos, contraseñas
                        y otros datos son encriptados, mezclados, codificados,
                        ocultados, desplazados o tratados de otra manera a través de 
                        alguna función o algoritmo. Al especificar una cadena de 
                        tratamiento parametrizada con este método, tal como 
                        <methodname>'MD5(?)'</methodname> o <methodname>'PASSWORD(?)'</methodname>, un 
                        desarrollador podría aplicar sentencias arbitrarias SQL 
                        sobre los datos credenciales de entrada. Ya que estas funciones 
                        son específicas de los RDBMS, debemos consultar el manual de la 
                        base de datos para comprobar la disponibilidad de tales 
                        funciones para su sistema de base de datos.
                    </para>
                </listitem>
            </itemizedlist>
        </para>
        <example id="zend.auth.adapter.dbtable.introduction.example.basic_usage">
            <title>Uso Básico</title>
            <para>
            	Como se explicó en la introducción, el constructor
            	<classname>Zend_Auth_Adapter_DbTable</classname> requiere una instancia 
            	de <classname>Zend_Db_Adapter_Abstract</classname> que sirve como 
            	conexión a la base de datos a la cual la instancia de autenticación 
            	está obligada a adaptarse. En primer lugar, la conexión de la base de 
            	datos debe ser creada.
            </para>
            <para>
                El siguiente código crea un adaptador para una base de datos en memoria
                , un esquema simple de la tabla, e inserta una fila contra la que se 
                pueda realizar una consulta de autenticación posterior. Este ejemplo 
                requiere que la extensión DOP SQLite esté disponible.
            </para>
             <programlisting language="php"><![CDATA[
// Crear una conexión en memoria de la bade de datos SQLite
$dbAdapter = new Zend_Db_Adapter_Pdo_Sqlite(array('dbname' =>
                                                  ':memory:'));

// Construir mediante una consulta una simple tabla
$sqlCreate = 'CREATE TABLE [users] ('
           . '[id] INTEGER  NOT NULL PRIMARY KEY, '
           . '[username] VARCHAR(50) UNIQUE NOT NULL, '
           . '[password] VARCHAR(32) NULL, '
           . '[real_name] VARCHAR(150) NULL)';

// Crear las credenciales de autenticación de la tabla
$dbAdapter->query($sqlCreate);

// Construir una consulta para insertar una fila para que se pueda realizar la autenticación
$sqlInsert = "INSERT INTO users (username, password, real_name) "
           . "VALUES ('my_username', 'my_password', 'My Real Name')";

// Insertar los datos
$dbAdapter->query($sqlInsert);
]]></programlisting>
            <para>
                Con la conexión de la base de datos y los datos de la tabla 
                disponibles, podemos crear un instancia de 
                <classname>Zend_Auth_Adapter_DbTable</classname>. Los valores de las opciones  
                de configuración pueden ser pasados al constructor o pasados como 
                parámetros a los métodos setter después de ser instanciados.
                </para>
             <programlisting language="php"><![CDATA[
// Configurar la instancia con los parámetros del constructor...
$authAdapter = new Zend_Auth_Adapter_DbTable(
    $dbAdapter,
    'users',
    'username',
    'password'
);

// ...o configurar la instancia con los métodos setter.
$authAdapter = new Zend_Auth_Adapter_DbTable($dbAdapter);

$authAdapter
    ->setTableName('users')
    ->setIdentityColumn('username')
    ->setCredentialColumn('password')
;
]]></programlisting>
            <para>
                En este punto, el adaptador de la instancia de autenticación está listo 
                para aceptar consultas de autenticación. Con el fin de elaborar una 
                consulta de autenticación, los valores de entrada de la credencial son 
                pasados por el adaptador ates de llamar al método 
                <methodname>authenticate()</methodname>:
            </para>
             <programlisting language="php"><![CDATA[
// Seleccionamos los valores de entrada de la credencial (e.g., de un formulario de acceso)
$authAdapter
    ->setIdentity('my_username')
    ->setCredential('my_password')
;

// Ejecutamos la consulta de autenticación, salvando los resultados
]]></programlisting>
            <para>
            	Además de la disponibilidad del método <methodname>getIdentity()</methodname> 
            	sobre el objeto resultante de la autenticación, 
            	<classname>Zend_Auth_Adapter_DbTable</classname> también ayuda a 
            	recuperar la fila de al tabla sobre la autenticación realizada.
                </para>
             <programlisting language="php"><![CDATA[
// Imprimir la identidad
echo $result->getIdentity() . "\n\n";

// Imprimir la fila resultado
print_r($authAdapter->getResultRowObject());

/* Salida:
my_username

Array
(
    [id] => 1
    [username] => my_username
    [password] => my_password
    [real_name] => My Real Name
)
]]></programlisting>
            <para>
                Ya que la fila de la tabla contiene el valor de la credencial, es 
                importante proteger los valores contra accesos no deseados.
            </para>
        </example>
    </sect2>
    <sect2 id="zend.auth.adapter.dbtable.advanced.storing_result_row">
        <title>Advanced Usage: Manteniendo el resultado del Objeto DbTable</title>
        <para>
        	Por defecto, <classname>Zend_Auth_Adapter_DbTable</classname> devuelve la 
        	identidad proporcionada al objeto Auth en la autenticación 
        	realizada. Otro de los casos de uso, donde los desarrolladores desean 
        	guardar para mantener el mecanismo de almacenamiento de un objeto identidad 
        	<classname>Zend_Auth</classname> que contiene información útil, se 
        	resuelve usando el método <methodname>getResultRowObject()</methodname> para devolver 
        	un objeto <methodname>stdClass</methodname>. El siguiente fragmento de código muestra 
        	su uso:
        </para>
         <programlisting language="php"><![CDATA[
// Autenticar con Zend_Auth_Adapter_DbTable
$result = $this->_auth->authenticate($adapter);

if ($result->isValid()) {
    // Almacena la identidad como un objedo dónde solo username y
    // real_name han sido devueltos
    $storage = $this->_auth->getStorage();
    $storage->write($adapter->getResultRowObject(array(
        'username',
        'real_name',
    )));

    // Almacena la identidad como un objeto dónde la columna contraseña ha
    // sido omitida
    $storage->write($adapter->getResultRowObject(
        null,
        'password'
    ));

    /* ... */

} else {

    /* ... */

}
]]></programlisting>
    </sect2>
    <sect2 id="zend.auth.adapter.dbtable.advanced.advanced_usage">
        <title>Ejemplo de Uso Avanzado</title>
        <para>
        	Si bien el objetivo primordial de <classname>Zend_Auth</classname> (y, 
        	por consiguiente, <classname>Zend_Auth_Adapter_DbTable</classname>) es 
        	principalmente la <emphasis>autenticación</emphasis> y no 
        	la <emphasis>autorización</emphasis>, hay unos pocos casos 
        	y problemas que se encuentran al límite entre cuales encajan dentro del 
        	dominio.
        	Dependiendo de cómo haya decidido explicar su problema, a veces tiene 
        	sentido resolver lo que podría parecer un problema de autorización 
        	dentro de un adaptador de autenticación.
        </para>
        <para>
            Con esa excepción fuera de lo común, 
            <classname>Zend_Auth_Adapter_DbTable</classname> ha construido mecanismos 
            que pueden ser aprovechados para realizar controles adicionales en la 
            autenticación a la vez que se resuelven algunos problemas comunes de los 
            usuarios.
        </para>
         <programlisting language="php"><![CDATA[
// El valor del campo status de una cuenta no es igual a "compromised"
$adapter = new Zend_Auth_Adapter_DbTable(
    $db,
    'users',
    'username',
    'password',
    'MD5(?) AND status != "compromised"'
);

// El valor del campo active de una cuenta es igual a "TRUE"
$adapter = new Zend_Auth_Adapter_DbTable(
    $db,
    'users',
    'username',
    'password',
    'MD5(?) AND active = "TRUE"'
]]></programlisting>
        <para>
            Otra idea puede ser la aplicación de un mecanismo de "salting". "Salting" 
            es un término que se refiere a una técnica que puede mejorar altamente la 
            seguridad de su aplicación. Se basa en la idea de concatenar una cadena 
            aleatoria a cada contraseña para evitar un ataque de fuerza bruta sobre la
            base de datos usando los valores hash de un diccionario pre-calculado.
        </para>
        <para>
            Por lo tanto, tenemos que modificar nuestra tabla para almacenar nuestra 
            cadena mezclada:
        </para>
         <programlisting language="php"><![CDATA[
$sqlAlter = "ALTER TABLE [users] "
          . "ADD COLUMN [password_salt] "
          . "AFTER [password]";
]]></programlisting>
        <para>
            Aquí hay una forma sencilla de generar una cadena mezclada por cada 
            usuario en el momento del registro:
        </para>
         <programlisting language="php"><![CDATA[
for ($i = 0; $i < 50; $i++) {
    $dynamicSalt .= chr(rand(33, 126));
]]></programlisting>
        <para>
            Y ahora vamos a construir el adaptador:
        </para>
         <programlisting language="php"><![CDATA[
$adapter = new Zend_Auth_Adapter_DbTable(
    $db,
    'users',
    'username',
    'password',
    "MD5(CONCAT('"
    . Zend_Registry::get('staticSalt')
    . "', ?, password_salt))"
);
]]></programlisting>
        <note>
            <para>
                Puede mejorar aún más la seguridad mediante el uso de un valor 
                'salt' estático fuertemente codificado en su aplicación. En el caso de 
                que su base de datos se vea comprometida (por ejemplo, por un ataque 
                de inyección SQL), su servidor web está intacto y sus 
                datos son inutilizable para el atacante.
            </para>
        </note>
        <para>
            Otra alternativa es utilizar el método <methodname>getDbSelect()</methodname> de 
            Zend_Auth_Adapter_DbTable después de que el adaptador se ha construido. 
            Este método devolverá la instancia del objeto Zend_Db_Select que se va a 
            utilizar para completar la rutina de authenticate(). Es importante señalar 
            que este método siempre devuelve el mismo objeto, independientemente de si 
            authenticate() ha sido llamado o no. Este objeto 
            <emphasis>no tendrá</emphasis> ninguna de las 
            credenciales de identidad o información de como estos valores son colocados 
            dentro del objeto seleccionado en authenticate().
        </para>
        <para>
            Un ejemplo de una situación en la que uno podría querer utilizar el 
            método getDbSelect() sería comprobar el estado de un usuario, en otras 
            palabras, ver si la cuenta del usuario está habilitada.
        </para>
         <programlisting language="php"><![CDATA[
// Continuando con el ejemplo de arriba
$adapter = new Zend_Auth_Adapter_DbTable(
    $db,
    'users',
    'username',
    'password',
    'MD5(?)'
);

// obtener el objeto select (por referencia)
$select = $adapter->getDbSelect();
$select->where('active = "TRUE"');

// authenticate, esto asegura que users.active = TRUE
$adapter->authenticate();
]]></programlisting>
    </sect2>
</sect1>
