<sect1 id="zend.acl.introduction">
    <title>Introducción</title>
    <para>
        <classname>Zend_Acl</classname> provee la implementación de un sistema simple y
        flexible de Listas de Control de Acceso (ACL, por sus siglas en
        inglés) para la administración de privilegios. En general, una
        aplicación puede utilizar las ACL para controlar el acceso a
        ciertos objetos protegidos, que son requeridos por otros
        objetos.
    </para>
    <para>
        Para los propósitos de esta documentación,
        <itemizedlist>
            <listitem>
                <para>
                    Un
                    <emphasis role="strong">recurso</emphasis>
                    es un objeto al cual el acceso esta controlado.
                </para>
            </listitem>
            <listitem>
                <para>
                    Un
                    <emphasis role="strong">rol</emphasis>
                    es un objeto que puede solicitar acceso a un
                    recurso.
                </para>
            </listitem>
        </itemizedlist>
        En términos generales,
        <emphasis role="strong">
            Los roles solicitan acceso a los recursos
        </emphasis>
        . Por ejemplo, si una persona solicita acceso a un automóvil,
        entonces la persona se convierte en el rol solicitante, y el
        automóvil en el recurso, puesto que el acceso al automóvil puede
        no estar disponible a cualquiera.
    </para>

    <para>
        A través de la especificación y uso de Listas de Control de
        Acceso (ACL), una aplicación puede controlar cómo los objetos
        solicitantes (roles) han obtenido acceso a objetos protegidos
        (recursos).
    </para>

    <sect2 id="zend.acl.introduction.resources">
        <title>Acerca de los Recursos</title>
        <para>
            En <classname>Zend_Acl</classname>, crear un recurso es muy sencillo. <classname>Zend_Acl</classname>
            proporciona el
            <classname>Zend_Acl_Resource_Interface</classname>
            para facilitar a los desarrolladores la creacción de
            recursos. Una clase solo necesita implementar su interfaz,
            la cual consiste en un método único,
            <code>getResourceId()</code>
            , para que <classname>Zend_Acl</classname> considere el objeto como un recurso.
            Adicionalmente,
            <classname>Zend_Acl_Resource</classname>
            es proporcionado por <classname>Zend_Acl</classname> como un recurso básico de
            aplicación  para que los desarrolladores puedan extenderla hasta
            donde lo deseen.
        </para>
        <para>
            <classname>Zend_Acl</classname> provee un estructura de árbol a la cual pueden ser
            agregados múltiples recursos (o "Áreas con Controles de
            Acceso").Ya que los recursos son almacenados en esta
            estructura de árbol, estos pueden ser organizados desde lo
            general (hacia la raíz del árbol) a lo específico (hacia las
            ramas del árbol). Consultas sobre un recurso específico
            buscarán automáticamente, en la jerarquía del
            recurso, reglas asignadas a recursos anteriores a los que
            el recurso actual haga referencia, permitiendo la herencia
            simple de reglas. Por ejemplo, si una regla por defecto se
            aplica a cada edificio en una ciudad, uno simplemente
            podría asignar la regla a la ciudad, en lugar de asignar la
            misma regla a cada edificio. Algunos edificios pueden
            necesitar excepciones a la regla, sin embargo, y esto es
            fácil de hacer en <classname>Zend_Acl</classname> asignando esta excepción a
            cada edificio que necesite una excepción a la regla. Un
            recurso sólo puede heredar de un recurso padre, aunque este
            recurso padre puede tener a la vez su propio recurso padre,
            y así; sucesivamente.
        </para>
        <para>
            <classname>Zend_Acl</classname> también soporta privilegios sobre recursos (ej.
            "crear","leer","actualizar", "borrar"), y el desarrollador
            puede asignar reglas que afecten o a todos los privilegios o
            a privilegios específicos sobre un recurso.
        </para>
    </sect2>

    <sect2 id="zend.acl.introduction.roles">
        <title>Acerca de las Reglas</title>
        <para>
            Al igual que los recursos, la creación de un rol
            también es muy simple. <classname>Zend_Acl</classname> proporciona
           <classname>Zend_Acl_Role_Interface</classname>
            para facilitar a los desarrolladores la creación de
            roles. Una clase solo necesita la implementación de su
            interfaz, la cual consiste en un método único,
            <code>getRoleId()</code>
            , para que <classname>Zend_Acl</classname> considere que el objeto es un Rol.
            Adicionalmente,
           <classname>Zend_Acl_Role</classname>
            está incluido con <classname>Zend_Acl</classname> como una implementación principal
            del rol para que los desarrolladores la extiendan hasta
            donde lo deseen.
        </para>
        <para>
            En <classname>Zend_Acl</classname>, un Rol puede heredar de otro o más roles. Esto
            es para soportar herencia de reglas entre roles. Por ejemplo,
            un Rol de usuario, como "sally", puede estar bajo uno o más
            roles padre, como "editor" y "administrador". El
            desarrollador puede asignar reglas a "editor" y
            "administrador" por separado, y "sally" puede heredar tales
            reglas de ambos, sin tener que asignar reglas directamente a
            "sally".
        </para>
        <para>
            Dado que la habilidad de herencia desde múltiples roles es
            muy util, múltiples herencias tambien introduce cierto grado
            de complejidad. El siguiente ejemplo ilustra la condición de
            ambiguedad y como <classname>Zend_Acl</classname> soluciona esto.
        </para>
        <example
            id="zend.acl.introduction.roles.example.multiple_inheritance">
            <title>Herencia Multiple entre Roles</title>
            <para>
                El siguiente código define tres roles principales - "
                <code>invitado</code>
                ", "
                <code>miembro</code>
                ", y "
                <code>admin</code>
                " - de los cuales otros roles pueden heredar. Entonces,
                un rol identificado como "
                <code>unUsuario</code>
                " es colocado y hereda de los otros tres roles. El orden en
                el cual estos roles aparecen en el array
                <code>$parents</code>
                es importante. Cuando es necesario, <classname>Zend_Acl</classname> busca por
                reglas de acceso definidas no solo para el rol
                solicitado (aquí, "
                <code>unUsuario</code>
                "), sino también sobre los roles heredados (aquí, "
                <code>invitado</code>
                ", "
                <code>miembro</code>
                ", y "
                <code>admin</code>
                "):
            </para>
            <programlisting role="php"><![CDATA[
require_once 'Zend/Acl.php';
$acl = new Zend_Acl();

require_once 'Zend/Acl/Role.php';
$acl->addRole(new Zend_Acl_Role('invitado'))
    ->addRole(new Zend_Acl_Role('miembro'))
    ->addRole(new Zend_Acl_Role('admin'));

$parents = array('invitado', 'miembro', 'admin');
$acl->addRole(new Zend_Acl_Role('unUsuario'), $parents);

require_once 'Zend/Acl/Resource.php';
$acl->add(new Zend_Acl_Resource('unRecurso'));

$acl->deny('invitado', 'unRecurso');
$acl->allow('miembro', 'unRecurso');

echo $acl->isAllowed('unUsuario', 'unRecurso') ? 'permitido' : 'denegado';]]>
            </programlisting>
            <para>
                Ya que no hay reglas específicamente definidas para
                el rol "
                <code>unUsuario</code>
                " y "
                <code>unRecurso</code>
                ", <classname>Zend_Acl</classname> debe buscar por reglas que puedan estar
                definidas para roles "
                <code>unUsuario</code>
                " hereda. Primero, el rol "
                <code>admin</code>
                " es visitado, y no hay regla de acceso definida
                para éste. Luego, el rol "
                <code>miembro</code>
                " es visitado, y <classname>Zend_Acl</classname> encuentra que aquí hay una
                regla especificando que "
                <code>miembro</code>
                " tiene permiso para acceder a "
                <code>unRecurso</code>
                ".
            </para>
            <para>
                Así, <classname>Zend_Acl</classname> va a seguir examinando las reglas definidas
                para otros roles padre, sin embargo, encontraría que "
                <code>invitado</code>
                " tiene el acceso denegado a "
                <code>unRecurso</code>
                ". Este hecho introduce una ambigüedad debido a que
                ahora "
                <code>unUsuario</code>
                " está tanto denegado como permitido para acceder a "
                <code>unRecurso</code>
                ", por la razon de tener un conflicto de reglas
                heredadas de diferentes roles padre.
            </para>
            <para>
                <classname>Zend_Acl</classname> resuelve esta ambiguedad completando la
                consulta cuando encuentra la primera regla que es
                directamente aplicable a la consulta. En este caso, dado
                que el rol "
                <code>miembro</code>
                " es examinado antes que el rol "
                <code>invitado</code>
                ", el código de ejemplo mostraría "
                <code>permitido</code>
                ".
            </para>
        </example>
        <note>
            <para>
                Cuando se especifican múltiples padres para un Rol, se
                debe tener en cuenta que el último padre listado es el
                primero en ser buscado por reglas aplicables para una
                solicitud de autorización.
            </para>
        </note>
    </sect2>

    <sect2 id="zend.acl.introduction.creating">
        <title>Creando las Listas de Control de Acceso (ACL)</title>

        <para>
            Una ACL puede representar cualquier grupo de objetos físicos
            o virtuales que desee. Para propósitos de demostración,
            sin embargo, crearemos un ACL básico para un Sistema de
            Administración de Contenido que mantendrá varias escalas de
            grupos sobre una amplia variedad de áreas. Para crear un
            nuevo objeto ACL, iniciamos la ACL sin parámetros:
        </para>

        <programlisting role="php"><![CDATA[
require_once 'Zend/Acl.php';

$acl = new Zend_Acl();]]>
        </programlisting>

        <note>
            <para>
                Hasta que un desarrollador especifique una regla
                "permitido", <classname>Zend_Acl</classname> deniega el acceso a cada privilegio
                sobre cada recurso para cada rol.
            </para>
        </note>
    </sect2>

    <sect2 id="zend.acl.introduction.role_registry">
        <title>Registrando Roles</title>

        <para>
            El Sistema de Administración de Contenido casi
            siempre necesita una jerarquía de permisos para determinar
            la capacidad de identificación de sus usuarios. Puede haber
            un grupo de 'Invitados' para permitir acceso limitado para
            demostraciones, un grupo de 'Personal' para la mayoría de
            usuarios del CMS quienes realizan la mayor parte de
            operaciones del día a día, un grupo 'Editores' para las
            responsabilidades de publicación, revisión, archivo y
            eliminación de contenido, y finalmente un grupo
            'Administradores' cuyas tareas pueden incluir todas las de los
            otros grupos y también el mantenimiento de la información
            delicada, manejo de usuarios, configuración de los datos
            básicos y su respaldo/exportación. Este grupo de permisos
            pueden ser representados en un registro de roles,
            permitiendo a cada grupo heredar los privilegios de los
            grupos 'padre', al igual que proporcionando distintos
            privilegios solo para su grupo individual. Los permisos pueden
            ser expresados como:
        </para>

        <table
            id="zend.acl.introduction.role_registry.table.example_cms_access_controls">
            <title>Controles de Acceso para un CMS de ejemplo</title>
            <tgroup cols="3">
                <thead>
                    <row>
                        <entry>Nombre</entry>
                        <entry>Permisos Individuales</entry>
                        <entry>Hereda permisos de</entry>
                    </row>
                </thead>
                <tbody>
                    <row>
                        <entry>Invitado</entry>
                        <entry>View</entry>
                        <entry>N/A</entry>
                    </row>
                    <row>
                        <entry>Personal</entry>
                        <entry>Editar, Enviar, Revisar</entry>
                        <entry>Invitado</entry>
                    </row>
                    <row>
                        <entry>Editor</entry>
                        <entry>Publicar, Archivar, Eliminar</entry>
                        <entry>Personal</entry>
                    </row>
                    <row>
                        <entry>Administrador</entry>
                        <entry>(Todos los accesos permitidos)</entry>
                        <entry>N/A</entry>
                    </row>
                </tbody>
            </tgroup>
        </table>

        <para>
            Para este ejemplo, se usa
           <classname>Zend_Acl_Role</classname>
            , pero cualquier objeto que implemente
           <classname>Zend_Acl_Role_Interface</classname>
            es admisible. Estos grupos pueden ser agragados al registro
            de roles de la siguiente manera:
        </para>

        <programlisting role="php"><![CDATA[
require_once 'Zend/Acl.php';

$acl = new Zend_Acl();

// Agregar grupos al registro de roles usando <classname>Zend_Acl</classname>_Role
require_once 'Zend/Acl/Role.php';

// Invitado no hereda controles de acceso
$rolInvitado = new Zend_Acl_Role('invitado');
$acl->addRole($rolInvitado);

// Personal hereda de Invitado
$acl->addRole(new Zend_Acl_Role('personal'), $rolInvitado);

/* alternativamente, lo de arriba puede ser escrito así:
$rolInvitado = $acl->addRole(new Zend_Acl_Role('personal'), 'invitado');
//*/

// Editor hereda desde personal
$acl->addRole(new Zend_Acl_Role('editor'), 'personal');

// Administrador no hereda controles de acceso
$acl->addRole(new Zend_Acl_Role('administrador'));]]>
        </programlisting>

    </sect2>

    <sect2 id="zend.acl.introduction.defining">
        <title>Definiendo Controles de Acceso</title>

        <para>
            Ahora que la ACL contiene los roles relevantes, se pueden
            establecer reglas que definan cómo los roles pueden acceder
            a los recursos. Tenga en cuenta que no definiremos ningún
            recurso en particular para este ejemplo, el cual está
            simplificado para ilustrar que las reglas se aplican a todos
            los recursos. <classname>Zend_Acl</classname> proporciona una forma práctica por la
            cual las reglas solo necesitan ser asignadas de lo general a
            lo especifico, minimizando el número de reglas necesarias,
            porque los recursos y roles heredan reglas que están
            definidas en sus padres.
        </para>

        <para>
            Consecuentemente, podemos definir un grupo razonablemente
            complejo de reglas con un mínimo de código. Para aplicar
            estos permisos básicos como están definidos arriba:
        </para>

        <programlisting role="php"><![CDATA[
require_once 'Zend/Acl.php';

$acl = new Zend_Acl();

require_once 'Zend/Acl/Role.php';

$rolInvitado = new Zend_Acl_Role('invitado');
$acl->addRole($rolInvitado);
$acl->addRole(new Zend_Acl_Role('personal'), $rolInvitado);
$acl->addRole(new Zend_Acl_Role('editor'), 'personal');
$acl->addRole(new Zend_Acl_Role('administrador'));

// Invitado solo puede ver el contenido
$acl->allow($rolInvitado, null, 'ver');

/* Lo de arriba puede ser escrito de la siguiente forma alternativa:
$acl->allow('invitado', null, 'ver');
//*/

// Personal hereda el privilegio de ver de invitado, pero también necesita privilegios adicionales
$acl->allow('personal', null, array('editar', 'enviar', 'revisar'));

// Editor hereda los privilegios de ver, editar, enviar, y revisar de personal,
// pero también necesita privilegios adicionales
$acl->allow('editor', null, array('publicar', 'archivar', 'eliminar'));

// Administrador no hereda nada, pero tiene todos los privilegios permitidos
$acl->allow('administrador');]]>
        </programlisting>

        <para>
            El valor
            <code>null</code>
            en las llamadas de
            <code>allow()</code>
            es usado para indicar que las reglas de permiso se aplican a
            todos los recursos.
        </para>

    </sect2>

    <sect2 id="zend.acl.introduction.querying">
        <title>Consultando la ACL</title>

        <para>
            Ahora tenemos una ACL flexible que puede ser usada para
            determinar qué solicitantes tienen permisos para realizar
            funciones a través de la aplicacion web. Ejecutar
            consultas es la forma más simple de usar el método
            <code>isAllowed()</code>
            :
        </para>

        <programlisting role="php"><![CDATA[
echo $acl->isAllowed('invitado', null, 'ver') ?
     "permitido" : "denegado"; // permitido

echo $acl->isAllowed('personal', null, 'publicar') ?
     "permitido" : "denegado"; // denegado

echo $acl->isAllowed('personal', null, 'revisar') ?
     "permitido" : "denegado"; // permitido

echo $acl->isAllowed('editor', null, 'ver') ?
     "permitido" : "denegado"; // permitido debido a la herencia de invitado

echo $acl->isAllowed('editor', null, 'actualizar') ?
     "permitido" : "denegado"; // denegado debido a que no hay regla de permiso para 'actualizar'

echo $acl->isAllowed('administrador', null, 'ver') ?
     "permitido" : "denegado"; // permitido porque administrador tiene permitidos todos los privilegios

echo $acl->isAllowed('administrador') ?
     "permitido" : "denegado"; // permitido porque administrador tiene permitidos todos los privilegios

echo $acl->isAllowed('administrador', null, 'actualizar') ?
     "permitido" : "denegado"; // permitido porque administrador tiene permitidos todos los privilegios]]>
        </programlisting>
    </sect2>
</sect1>
<!--
    vim:se ts=4 sw=4 et:
-->
