Symfony 1.0, la guía definitiva

6.5. Seguridad de la Acción

La posibilidad de ejecutar una acción puede ser restringida a usuarios con ciertos privilegios. Las herramientas proporcionadas por Symfony para este propósito permiten la creación de aplicaciones seguras, en las que los usuarios necesitan estar autenticados antes de acceder a alguna característica o a partes de la aplicación. Añadir esta seguridad a una aplicación requiere dos pasos: declarar los requerimientos de seguridad para cada acción y autenticar a los usuarios con privilegios para que puedan acceder estas acciones seguras.

6.5.1. Restricción de Acceso

Antes de ser ejecutada, cada acción pasa por un filtro especial que verifica si el usuario actual tiene privilegios de acceder a la acción requerida. En Symfony, los privilegios estan compuestos por dos partes:

  • Las acciones seguras requieren que los usuarios esten autenticados.
  • Las credenciales son privilegios de seguridad agrupados bajo un nombre y que permiten organizar la seguridad en grupos.

Para restringir el acceso a una acción se crea y se edita un archivo de configuración YAML llamado security.yml en el directorio config/ del módulo. En este archivo, se pueden especificar los requerimientos de seguridad que los usuarios deberán satisfacer para cada acción o para todas (all) las acciones. El listado 6-23 muestra un ejemplo de security.yml.

Listado 6-23 - Estableciendo restricciones de acceso, en apps/miaplicacion/modules/mimodulo/config/security.yml

ver:
  is_secure:   off       # Todos los usuarios pueden ejecutar la acción "ver"

modificar:
  is_secure:   on        # La acción "modificar" es sólo para usuarios autenticados

borrar:
  is_secure:   on        # Sólo para usuarios autenticados
  credentials: admin     # Con credencial "admin"

all:
  is_secure:  off        # off es el valor por defecto

Las acciones no incluyen restricciones de seguridad por defecto, asi que cuando no existe el archivo security.yml o no se indica ninguna acción en ese archivo, todas las acciones son accesibles por todos los usuarios. Si existe un archivo security.yml, Syfmony busca por el nombre de la acción y si existe, verifica que se satisfagan los requerimientos de seguridad. Lo que sucede cuando un usuario trata de acceder una acción restringida depende de sus credenciales:

  • Si el usuario está autenticado y tiene las credenciales apropiadas, entonces la acción se ejecuta.
  • Si el usuario no está autenticado, es redireccionado a la acción de login.
  • Si el usuario está autenticado, pero no posee las credenciales apropiadas, será redirigido a la acción segura por defecto, como muestra la figura 6-1.

Las páginas login y secure son bastante simples, por lo que seguramente será necesario personalizarlas. Se puede configurar que acciones se ejecutan en caso de no disponer de suficientes privilegios en el archivo settings.yml de la aplicación cambiando el valor de las propiedades mostradas en el listado 6-24.

La página por defecto de la acción <code>secure</code>

Figura 6.1 La página por defecto de la acción secure

Listado 6-24 - Las acciones de seguridad por defecto se definen en apps/miaplicacion/config/settings.yml

all:
  .actions:
    login_module:           default
    login_action:           login

    secure_module:          default
    secure_action:          secure

6.5.2. Otorgando Acceso

Para obtener acceso a áreas restringidas, los usuarios necesitan estar autenticados y/o poseer ciertas credenciales. Puedes extender los privilegios del usuario mediante llamadas a métodos del objeto sfUser. El estado autenticado se establece con el método setAuthenticated() y se puede comprobar con el método isAuthenticated(). El listado 6-25 muestra un ejemplo sencillo de autenticación.

Listado 6-25 - Estableciendo el estado de autenticación del usuario

class miCuentaActions extends sfActions
{
  public function executeLogin()
  {
    if ($this->getRequestParameter('login') == 'valor')
    {
      $this->getUser()->setAuthenticated(true);
    }
  }

  public function executeLogout()
  {
    if ($this->getUser()->isAuthenticated())
    {
      $this->getUser()->setAuthenticated(false);
    }
  }
}

Las credenciales son un poco más complejas de tratar, ya que se pueden verificar, agregar, quitar y borrar. El listado 6-26 describe los métodos de las credenciales de la clase sfUser.

Listado 6-26 - Manejando las credenciales del usuario en la acción

class miCuentaActions extends sfActions
{
  public function executeEjemploDeCredenciales()
  {
    $usuario = $this->getUser();

    // Agrega una o más credenciales
    $usuario->addCredential('parametro');
    $usuario->addCredentials('parametro', 'valor');

    // Verifica si el usuario tiene una credencial
    echo $usuario->hasCredential('parametro');                         => true

    // Verifica si un usuario tiene una de las credenciales
    echo $usuario->hasCredential(array('parametro', 'valor'));         => true

    // Verifica si el usuario tiene ambas credenciales
    echo $usuario->hasCredential(array('parametro', 'valor'), true);   => true

    // Quitar una credencial
    $usuario->removeCredential('parametro');
    echo $usuario->hasCredential('parametro');                         => false

    // Elimina todas las credenciales (útil en el proceso de logout)
    $usuario->clearCredentials();
    echo $usuario->hasCredential('valor');                             => false
  }
}

Si el usuario tiene la credencial "parametro", entonces ese usuario podrá acceder a las acciones para las cuales el archivo security.yml requiere esa credencial. Las credenciales se pueden utilizar también para mostrar contenido autenticado en una plantilla, como se muestra en el listado 6-27.

Listado 6-27 - Tratando con credenciales de usuario en una plantilla

<ul>
  <li><?php echo link_to('seccion1', 'content/seccion1') ?></li>
  <li><?php echo link_to('seccion2', 'content/seccion2') ?></li>
  <?php if ($sf_user->hasCredential('seccion3')): ?>
  <li><?php echo link_to('seccion3', 'content/seccion3') ?></li>
  <?php endif; ?>
</ul>

Y para el estado de autenticación, las credenciales normalmente se dan a los usuarios durante el proceso de login. Este es el motivo por el que el objeto sfUser normalmente se extiende para añadir métodos de login y de logout, de forma que se pueda establecer el estado de seguridad del usuario de forma centralizada.

Truco Entre los plugins de Symfony, sfGuardPlugin extiende la clase de sesión para facilitar el proceso de login y logout. El Capitulo 17 contiene más información al respecto.

6.5.3. Credenciales Complejas

La sintaxis YAML utilizada en el archivo security.yml permite restringir el acceso a usuarios que tienen una combinación de credenciales, usando asociaciones de tipo AND y OR. Con estas combinaciones, se pueden definir flujos de trabajo y sistemas de manejo de privilegios muy complejos -- como por ejemplo, un sistema de gestión de contenidos (CMS) cuya parte de gestión sea accesible solo a usuarios con credencial admin, donde los artículos pueden ser editados solo por usuarios con credenciales de editor y publicados solo por aquellos que tienen credencial de publisher. El listado 6-28 muestra este ejemplo.

Listado 6-28 - Sintaxis de combinación de credenciales

editarArticulo:
  credentials: [ admin, editor ]              # admin AND editor

publicarArticulo:
  credentials: [ admin, publisher ]           # admin AND publisher

gestionUsuarios:
  credentials: [[ admin, superuser ]]         # admin OR superuser

Cada vez que se añade un nuevo nivel de corchetes, la lógica cambia entre AND y OR. Así que se pueden crear combinaciones muy complejas de credenciales, como la siguiente:

credentials: [[root, [supplier, [owner, quasiowner]], accounts]]
             # root OR (supplier AND (owner OR quasiowner)) OR accounts