<?xml version="1.0" encoding="UTF-8"?>
<sect1 id="zend.auth.introduction">
    <title>Introducción</title>
    <para>
        Zend_Auth provee una API para autenticación e incluye adaptadores concretos de autenticación para
        escenarios de casos de uso común.
    </para>
    <para>
        Zend_Auth es concerniente sólo con <emphasis role="strong">autenticación</emphasis> y no con
        <emphasis role="strong">autorización</emphasis>. Autenticación es vagamente definido como: determinar
        si una entidad realmente es lo que pretende ser (o sea, identificación), basandose en un grupo de
    credenciales. Autorización, el proceso de decidir si se permite a una entidad: acceso a, o el
    realizar operaciones en, otras entidades esta fuera del alcance de Zend_Auth. Para más información sobre
    autorización y control de acceso con Zend Framework, por favor vea
    <link linkend="zend.acl">Zend_Acl</link>.
    </para>
    <note>
        <para>
            La clase <code>Zend_Auth</code> implementa el patrón Singleton - sólo una instancia de la clase está
            disponible - a través de su método estático <code>getInstance()</code>. Esto significa que usar el operador <code>new</code>
            y la keyword <code>clone</code> no va a funcionar con la clase <code>Zend_Auth</code> : use
            <code>Zend_Auth::getInstance()</code> en su lugar.
        </para>
    </note>
    <sect2 id="zend.auth.introduction.adapters">

        <title>Adaptadores</title>

        <para>
            Un adaptador Zend_Auth es usado para autenticar en contra de un tipo particular de servicio de autenticación,
            como LDAP, RDBMS, o almacenamiento basado en ficheros. Diferentes adaptadores pueden tener opciones y compotamientos
            muy diferentes, pero algunas cosas básicas son comunes entre los adaptadores de autenticación. Por ejemplo,
            aceptar credenciales de autenticación (incluyendo una identidad supuesta), realizar consultas ante el
            servicio de autenticación, y regresar resultados, son comunes para los adaptadores Zend_Auth.
        </para>

        <para>
            Cada clase adaptadora Zend_Auth implementa <code>Zend_Auth_Adapter_Interface</code>. Esta interface define un
            metodo, <code>authenticate()</code>, que la clase adaptadora debe implementar para realizar una peticion de
            autenticación. Cada clase adaptadora debe ser preparada antes de llamar a <code>authenticate()</code>. Esta preparación
            del adaptador incluye la creación de credenciales (p.ej. nombre de usuario y contraseña) y la definición de valores para opciones
            de configuración especificos del adaptador, como valores de coneccion a base de datos para un adaptador de tabla de base de datos.
        </para>

        <para>
            El siguente ejemplo es un adaptador de autenticación que requiere que un nombre de usuario y contraseña sean especificados
            para la autenticación. Otros detalles, como la forma de realizar peticiones al servicio de autenticación, han sido
            omitídos por brevedad:

            <programlisting role="php"><![CDATA[
class MyAuthAdapter implements Zend_Auth_Adapter_Interface
{
    /**
     * Establece nombre de usuario y contraseña para autenticacón
     *
     * @return void
     */
    public function __construct($username, $password)
    {
        // ...
    }

    /**
     * Realiza un intento de autenticación
     *
     * @throws Zend_Auth_Adapter_Exception Si la autenticación no puede
     *                                     ser realizada
     * @return Zend_Auth_Result
     */
    public function authenticate()
    {
        // ...
    }
}
]]>
            </programlisting>

            Como se ha indicado en su docblock, <code>authenticate()</code> debe regresar una instancia de
            <code>Zend_Auth_Result</code> (o de una clase derivada de <code>Zend_Auth_Result</code>). Si por alguna
            razón es imposible realizar una petición de autenticación, <code>authenticate()</code> debería arrojar
            una excepción que se derive de <code>Zend_Auth_Adapter_Exception</code>.
        </para>

    </sect2>

    <sect2 id="zend.auth.introduction.results">

        <title>Resultados</title>

        <para>
            Los adaptadores Zend_Auth regresan una instancia de <code>Zend_Auth_Result</code> con
            <code>authenticate()</code> para representar el resultado de un intento de autenticación. Los adaptadores
            llenan el objeto <code>Zend_Auth_Result</code> en cuanto se construye, así que los siguientes cuatro métodos
            proveen un grupo básico de operaciones "frente al usuario" que son comunes a los resultados de adaptadores Zend_Auth:
            <itemizedlist>
                <listitem>
                    <para>
                        <code>isValid()</code> - regresa true si y solo si el resultado representa un
                        intento de autenticación exitoso
                    </para>
                </listitem>
                <listitem>
                    <para>
                        <code>getCode()</code> - regresa una constante identificadora <code>Zend_Auth_Result</code> para
                        determinar el tipo de fallo en la autenticación o si ha sido exitosa. Este puede ser usado
                        en situaciones cuando el desarrollador desea distinguir entre varios tipos de resultados
                        de autenticación. Esto permite a los desarrolladores, por ejemplo, mantener estadísticas
                        detalladas de los resultados de autenticación. Otro uso de esta característica es: proporcionar
                        al usuario mensajes específicos detallados por razones de usabilidad, aunque los desarrolladores
                        son	exhortados a considerar el riesgo de proporcionar tales detalles a los usuarios, en vez de
                        un mensaje general de fallo en la autenticación. Para más información, vea las siguientes notas:
                    </para>
                </listitem>
                <listitem>
                    <para>
                        <code>getIdentity()</code> - regresa la identidad del intento de autenticación
                    </para>
                </listitem>
                <listitem>
                    <para>
                        <code>getMessages()</code> - regresa un arreglo de mensajes pertinentes a un fallido
                        intento de autenticación
                    </para>
                </listitem>
            </itemizedlist>
        </para>

        <para>
            El desarrollador podría desear ramificar basado en el tipo de resultado de la autenticación a fin de
            realizar operaciones mas específicas. Algunas operaciones que los desarrolladores podrían encontrar útiles
            son: bloquear cuentas despues de varios intentos fallidos de ingresar una contraseña, marcar una dirección IP
            despues de que ha intentado muchas identidades no existentes, y porporcionar al usuario mensajes especificos
            resultados de la autenticación. Los siguientes codigos de resultado están disponibles:

            <programlisting role="php"><![CDATA[
Zend_Auth_Result::SUCCESS
Zend_Auth_Result::FAILURE
Zend_Auth_Result::FAILURE_IDENTITY_NOT_FOUND
Zend_Auth_Result::FAILURE_IDENTITY_AMBIGUOUS
Zend_Auth_Result::FAILURE_CREDENTIAL_INVALID
Zend_Auth_Result::FAILURE_UNCATEGORIZED
]]>
            </programlisting>

        </para>

        <para>
            El siguiente ejemplo ilustra como un desarrollador podría ramificar basado en el código resultado:

            <programlisting role="php"><![CDATA[
// debtri de AuthController / loginAction
$result = $this->_auth->authenticate($adapter);

switch ($result->getCode()) {

    case Zend_Auth_Result::FAILURE_IDENTITY_NOT_FOUND:
        /** realiza algo para identidad inexistente **/
        break;

    case Zend_Auth_Result::FAILURE_CREDENTIAL_INVALID:
        /** realiza algo para credencial invalida **/
        break;

    case Zend_Auth_Result::SUCCESS:
        /** realiza algo para autenticación exitosa **/
        break;

    default:
        /** realiza algo para otras fallas **/
        break;
}
]]>
            </programlisting>

        </para>

    </sect2>

    <sect2 id="zend.auth.introduction.persistence">

        <title>Persistencia de Identidad</title>

        <para>
            Autenticar una petición que incluye credenciales de autenticación es util por sí mismo, pero también
            es importante el soportar mantener la identidad autenticada sin tener que presentar las credenciales
            de autenticación con cada petición.
        </para>

        <para>
            HTTP es un protocolo sin estado, sin embargo, se han desarrollado técnicas como las cookies y sesiones
            a fin de facilitar mantener el estado a través de multiples peticiones en aplicaciones web del lado del servidor.
        </para>

        <sect3 id="zend.auth.introduction.persistence.default">

            <title>Persistencia por Defecto en la Sesión PHP</title>

            <para>
                 Por defecto, <code>Zend_Auth</code> provee almacenamiento persistente de la identidad desde un intento
                 de autenticación exitoso usando la sesión PHP. En un intento de autenticación exitoso,
                 <code>Zend_Auth::authenticate()</code> almacena la identidad del resultado de autenticación en
                 almacenamiento persistente. A menos que se configure diferente, <code>Zend_Auth</code> usa una clase de
                 almacenamiento llamada <code>Zend_Auth_Storage_Session</code>, la cual, a su vez usa
                 <link linkend="zend.session">Zend_Session</link>. Una clase diferente podría ser utilizada mediante
                 proveer un objeto que implemente <code>Zend_Auth_Storage_Interface</code> a <code>Zend_Auth::setStorage()</code>
            </para>

            <note>
                <para>
                    Si el automático almacenamiento persistente de la identidad no es apropiado para un caso en particular,
                    entonces los desarrolladores podrían dejar de usar la clase <code>Zend_Auth</code> al mismo tiempo,
                    utilizando en su lugar una clase adaptadora directamente.
                </para>
            </note>

            <example id="zend.auth.introduction.persistence.default.example">

                <title>Modifying the Session Namespace</title>

                <para>
                    <code>Zend_Auth_Storage_Session</code> usa un espacionombre (namespace) de sesión <code>'Zend_Auth'</code>.
                    Este espacio-nombre podría ser OVERRIDDEN al pasar un valor diferente al contructor de
                    <code>Zend_Auth_Storage_Session</code>, y este valor es pasado internamente al constructor de
                    <code>Zend_Session_Namespace</code>. Esto debería ocurrir antes de que se intente la autenticación, ya que
                    <code>Zend_Auth::authenticate()</code> realiza el almacenamiento automático de la identidad.

                    <programlisting role="php"><![CDATA[
// Almacena una referencia a la instancia Singleton de Zend_Auth
$auth = Zend_Auth::getInstance();

// Usa 'unEspacionombre' en lugar de 'Zend_Auth'
$auth->setStorage(new Zend_Auth_Storage_Session('unEspacionombre'));

/**
 * @todo Set up the auth adapter, $authAdapter
 */

// Autenticar, almacenando el resultado, y persistiendo la identidad en
// suceso
$result = $auth->authenticate($authAdapter);
]]>
                    </programlisting>

                </para>

            </example>

        </sect3>

        <sect3 id="zend.auth.introduction.persistence.custom">

            <title>Implementando Almacenamiento Personalizado</title>

            <para>
                En ocaciones los desarrolladores podrían necesitar usar un diferente comportamiento de persistencia	de identidad
                que el provisto por <code>Zend_Auth_Storage_Session</code>. Para esos casos los desarrolladores podrían simplemente
                implementar <code>Zend_Auth_Storage_Interface</code> y suplir una instancia de la clase a
                <code>Zend_Auth::setStorage()</code>.
            </para>

            <example id="zend.auth.introduction.persistence.custom.example">

                <title>Usando una Clase de Almacenamiento Personalizada</title>

                <para>
                    Para poder utilizar una clase de almacenamiento persistente de identidad diferente a
                    <code>Zend_Auth_Storage_Session</code>, el desarrollador implementa <code>Zend_Auth_Storage_Interface</code>:

                    <programlisting role="php"><![CDATA[
class MyStorage implements Zend_Auth_Storage_Interface
{
    /**
     * Regresa true si y solo si el almacenamiento esta vacio
     *
     * @arroja Zend_Auth_Storage_Exception Si es imposible
     *                                     determinar si el almacenamiento
     *                                     esta vacio
     * @regresa boleano
     */
    public function isEmpty()
    {
        /**
         * @por hacer implementación
         */
    }

    /**
     * Regresa el contenido del almacenamiento
     *
     * El comportamiento es indefinido cuando el almacenamiento esta vacio
     *
     * @arroja Zend_Auth_Storage_Exception Si leer contenido de
     *                                     almacenamiento es imposible
     * @regresa mixto
     */
    public function read()
    {
        /**
         * @por hacer implementación
         */
    }

    /**
     * Escribe $contents al almacenamiento
     *
     * @parametros mezclado $contents
     * @arroja Zend_Auth_Storage_Exception Si escribir $contents al
     *                                     almacenamiento es imposible
     * @regresa boleano
     */
    public function write($contents)
    {
        /**
         * @por hacer implementación
         */
    }

    /**
     * limpia contenidos del almacenamiento
     *
     * @arroja Zend_Auth_Storage_Exception Si limpiar contenidos del
     *                                     almacenamiento es imposible
     * @regresa void
     */
    public function clear()
    {
        /**
         * @por hacer implementación
         */
    }
}
]]>
                    </programlisting>

                </para>

                <para>
                    A fin de poder usar esta clase de almacenamiento personalizada, <code>Zend_Auth::setStorage()</code>
                    es invocada antes de intentar una petición de autenticación:

                    <programlisting role="php"><![CDATA[
// Instruye Zend_Auth para usar la clase de almacenamiento personalizada
Zend_Auth::getInstance()->setStorage(new MyStorage());

/**
 * @por hacer Configurar el adaptador de autenticación, $authAdapter
 */

// Autenticar, almacenando el resultado, y persistiendo la identidad
// si hay exito
$result = Zend_Auth::getInstance()->authenticate($authAdapter);
]]>
                    </programlisting>

                </para>

            </example>

        </sect3>

    </sect2>

    <sect2 id="zend.auth.introduction.using">

        <title>Usando Zend_Auth</title>

        <para>
            Hay dos formas provistas de usar adaptadores Zend_Auth:
            <orderedlist>
            <listitem>
                <para>
                    indirectamente, a través de <code>Zend_Auth::authenticate()</code>
                </para>
            </listitem>
            <listitem>
                <para>
                    directamente, a través del metodo<code>authenticate()</code> del adaptador
                </para>
            </listitem>
            </orderedlist>
        </para>

        <para>
            El siguiente ejemplo ilustra como usar el adaptador Zend_Auth indirectamente, a través
            del uso de la clase <code>Zend_Auth</code>:

            <programlisting role="php"><![CDATA[
// Recibe una referencia a la instancia singleton de Zend_Auth
$auth = Zend_Auth::getInstance();

// Configura el adaptador de autenticación
$authAdapter = new MyAuthAdapter($username, $password);

// Intenta la autenticación, almacenando el resultado
$result = $auth->authenticate($authAdapter);

if (!$result->isValid()) {
    // Fautenticación fallida: imprime el por que
    foreach ($result->getMessages() as $message) {
        echo "$message\n";
    }
} else {
    // Autenticación exitosa, la identidad ($username) es almacenada
    // en la sesión
    // $result->getIdentity() === $auth->getIdentity()
    // $result->getIdentity() === $username
}
]]>
            </programlisting>
        </para>

        <para>
            Una vez que la autenticación ha sido intentada en una petición, como en el ejemplo anterior,
            es fácil verificar si existe una identidad autenticada exitosamente:
            <programlisting role="php"><![CDATA[
$auth = Zend_Auth::getInstance();
if ($auth->hasIdentity()) {
    // Existe la identidad; obtenla
    $identity = $auth->getIdentity();
}
]]>
            </programlisting>
        </para>

        <para>
            Para remover una identidad del almacenamiento persistente, simplemente usa el metodo <code>clearIdentity()</code>method.
            Comunmente esto sería usado para implementar una operación "cerrar sesión" en la aplicación:
            <programlisting role="php"><![CDATA[
Zend_Auth::getInstance()->clearIdentity();
]]>
            </programlisting>
        </para>

        <para>
            Cuando el uso automático de almacenamiento persistente es inapropiado para un caso en particular,
            el desarrollador podría simplemente omitir el uso de la clase <code>Zend_Auth</code>, usando una
            clase adaptadora directamente. El uso directo de una clase adaptadora implica configurar y preparar
            un objeto adaptador y despues llamar a su metodo <code>authenticate()</code>. Los detalles específicos
            del adaptador son discutidos en la documentación de cada adaptador. El siguiente ejemplo utiliza
            directamente <code>MyAuthAdapter</code>:

            <programlisting role="php"><![CDATA[
// Configura el adaptador de autenticación
$authAdapter = new MyAuthAdapter($username, $password);

// Intenta la autenticación, almacenando el resultado
$result = $authAdapter->authenticate();

if (!$result->isValid()) {
    // Autenticación fallida, imprime el porque
    foreach ($result->getMessages() as $message) {
        echo "$message\n";
    }
} else {
    // Autenticación exitosa
    // $result->getIdentity() === $username
}
]]>
            </programlisting>
        </para>

    </sect2>

</sect1>
<!--
vim:se ts=4 sw=4 et:
-->