2. ACL
Access Control Lists
Listas para el Control de Acceso
Gonzalo Alonso
gonkpo@gmail.com
@GonzaloAlonsoD
http://groups.google.com/group/symfony-2-argentina
3. ACL
En aplicaciones complejas, a menudo te
enfrentas al problema de que las decisiones de
acceso no se pueden basar únicamente en la
persona (Token) que está solicitando el acceso,
sino también implica un objeto dominio al cual se
está solicitando acceso. Aquí es donde entra en
juego el sistema ACL.
4. Escenario
Imagina que estas diseñando un sistema de blog
donde un usuario puede administrarlo y publicar
sus propias entradas. En este escenario,
Entrada sería nuestro objeto dominio al cual
deseas restringir el acceso. Podrías tomar varios
enfoques para lograr esto usando Symfony2,
dos enfoques básicos (no exhaustivos) son:
5. Reforzar la seguridad en los métodos de tu
negocio:
Básicamente, significa mantener una referencia
dentro de cada comentario a todos los usuarios
que tienen acceso, y luego comparar estos
usuarios al Token provisto.
Reforzar la seguridad con roles:
En este enfoque, debes agregar un rol a cada
objeto comentario, es decir,
ROLE_COMMENT_1, ROLE_COMMENT_2, etc.
6. Tomar una decisión
Los 2 métodos nombrados anteriormente son
validos, afortunadamente, hay una manera
mejor, de la cual hablaremos ahora.
7. Proceso de Arranque
(bootstrapping):
En primer lugar, tienes que configurar la
conexión al sistema ACL que se supone vas a
usar:
YAML
# app/config/security.yml
security:
acl:
connection: default
8. Generar estructura de la base de
datos:
Después de configurar la conexión, importamos
la estructura de la base de datos.
Afortunadamente, existe una tarea para eso.
Basta con ejecutar la siguiente orden:
$ php app/console init:acl
12. En primer lugar ->createAcl() no acepta objetos
de dominio directamente, sino sólo
implementaciones de ObjectIdentityInterface.
Este paso adicional te permite trabajar con ACL,
incluso cuando no tienes a mano ninguna
instancia real del objeto dominio. Será muy útil si
deseas comprobar los permisos de un gran
número de objetos sin tener que hidratar estos
objetos.
13. Recupero usuario logueado:
// recupera la identidad de seguridad del usuario
// registrado actualmente
$securityContext = $this->get('security.context');
$user = $securityContext->getToken()-
>getUser();
$securityIdentity =
UserSecurityIdentity::fromAccount($user);
14. Otorgo los permisos:
// otorga permiso de propietario
$acl->insertObjectAce($securityIdentity,
MaskBuilder::MASK_OWNER);
$aclProvider->updateAcl($acl);
15. La otra parte interesante es la llamada a
->insertObjectAce(). En el ejemplo, estas
otorgando acceso de propietario al comentario al
usuario que ha iniciado sesión.
MaskBuilder::MASK_OWNER es una máscara de
bits enteros predefinida; no te debe preocupar
que el constructor de la máscara abstraiga la
mayoría de los detalles técnicos, porque gracias a
esta técnica puedes almacenar muchos permisos
diferentes en la fila de la base de datos, lo cual te
da un considerable impulso en rendimiento.
16. Comprobando el acceso:
$securityContext = $this->get('security.context');
// verifica el acceso para edición
if (false === $securityContext->isGranted('EDIT',
$entrada))
{
throw new AccessDeniedException();
}
// recupera el objeto entrada, y realiza tu edición
17. Permisos acumulados
En el ejemplo, sólo concediste al usuario el
permiso OWNER base. Si bien este además
permite efectivamente al usuario realizar
cualquier operación, como ver, editar, etc., sobre
el objeto dominio, hay casos en los que deseas
conceder explícitamente estos permisos.
18. Crear máscaras con MaskBuilder
$builder = new MaskBuilder();
$builder
->add('view')
->add('edit')
->add('delete')
->add('undelete')
;
$mask = $builder->get(); // int(29)
19. Utilizar máscara creada
Esta máscara de bits de enteros, se puede utilizar para
conceder a un usuario los permisos base añadidos
anteriormente:
$identity = new UserSecurityIdentity('david',
'AcmeUserBundleEntityUser');
$acl->insertObjectAce($identity, $mask);
El usuario ahora puede ver, editar, borrar, y recuperar objetos
eliminados.