2011-09-13 5 views
16

Esta pregunta surgió al diseñar un sistema de ACL dedicado para una aplicación personalizada, pero creo que se aplica a los sistemas de ACL en general, ya que no he descubierto cómo abordar este problema mirando algunos de los sistemas principales, como Zend_ACL.construyendo un sistema de ACL dinámico OO 'bidireccional'

En mi aplicación, los permisos se otorgan dinámicamente, por ejemplo: un usuario obtiene permisos de vista en una actividad porque es un miembro del equipo al que está vinculada la actividad. Esto se basa en la suposición de que siempre tiene un Employee (usuario) que quiere realizar una acción (ver/editar/etc) en un Item (uno de los objetos en mi aplicación, por ejemplo, Actividad, Equipo, etc.). Esto es suficiente para mi uso específico;

$Activity = new Activity($_POST['activity_id']); 

$Acl = new Acl($Activity); 
if (!$Acl->check('edit') { 
    throw new AclException('no permission to edit'); 
} 

Mi clase Acl contiene todas las reglas de negocio para conceder los permisos, y son creados 'sobre la marcha' (aunque a veces en caché por motivos de rendimiento);

/** 
* Check the permissions on a given activity. 
* @param Activity $Activity 
* @param int $permission (optional) check for a specific permission 
* @return mixed integer containing all the permissions, or a bool when $permission is set 
*/ 
public function checkActivity(Activity $Activity, $permission = null) { 
    $permissions = 0; 

    if ($Activity->owner_actor_id == $this->Employee->employee_id) { 
     $permissions |= $this->activity['view']; 
     $permissions |= $this->activity['remove']; 
     $permissions |= $this->activity['edit']; 
    } elseif (in_array($this->Employee->employee_id, $Activity->contributor_ids_arr)) { 
     $permissions |= $this->activity['view']; 
    } else { 
     /** 
     * Logged in user is not the owner of the activity, he can contribute 
     * if he's in the team the activity is linked to 
     */ 
     if ($Activity->getTeam()->isMember($this->Employee)) { 
      $permissions |= $this->activity['view']; 
     } 
    } 

    return ($permission ? (($permission & $permissions) === $permission) : $permissions); 
} 

Este sistema funciona bien tal como está.

El problema con este enfoque surge cuando quiere 'revertir' las reglas de la ACL. Por ejemplo, "buscar todas las actividades que tengo permiso para editar". No quiero poner ninguna lógica como WHERE owner_actor_id = $Employee->employee_id en el código que necesita las actividades, porque esta es la responsabilidad de la clase Acl y debe mantenerse centralizada. Con la implementación actual, no tengo otra opción que recuperar todas las actividades en el código y luego afirmarlas una a una. Este es, por supuesto, un enfoque muy ineficiente.

Lo que estoy buscando es algunas ideas sobre una buena arquitectura (o un puntero a una implementación de ACL existente o algunos patrones de diseño pertinentes) para crear un sistema de ACL que de alguna manera puede hacer ambas cosas hasPermission($Item, $permission)fetchAllItems($permission) y, a ser posible con el el mismo conjunto de reglas comerciales.

¡Gracias a todos por adelantado!


He mirado en la implementación Zend_ACL, sino que se centra más en los permisos generales. También encontré las siguientes preguntas aquí en SO:

Pero, lamentablemente, no parecen responder a la pregunta tampoco.

+0

¿Cuál es el argumento en contra de poner los 'fetchAllItems()' en el método 'Clase Acl'? No estoy seguro de entender realmente la pregunta. – erisco

Respuesta

1

Un colega me ofreció otra opinión al respecto, esa también podría ser la solución a este problema.

Lo que pensaron que quería se poner todo el código relacionado con el acceso en la clase ACL (mirroring mi afirmación de que "no quiere poner ninguna lógica como WHERE owner_actor_id = $Employee->employee_id en el código que necesita de las actividades, porque esta es la responsabilidad de la clase Acl y debe mantenerse centralizada. ").

Lo que realmente quiero es a asegúrese de que el usuario nunca puede acceder algo que no se ajuste a las normas que figuran en la clase de ACL.No es realmente un problema si el 'código de trabajador' ya obtiene un subconjunto de los datos, siempre y cuando se compruebe finalmente contra la ACL 'real'. Lo peor que puede pasar es que el usuario vea menos de lo que debería, lo que es mucho mejor que más.

Con esta 'solución' (enfoque alternativo, si lo desea), evitará obtener todos los datos, manteniendo el beneficio de tener todas las reglas en un solo lugar. Cualquier otra solución que se me ocurra involucraría una duplicación de las reglas, ya que necesita reglas en PHP para verificar un recurso dado, y reglas escritas en MySQL para obtener todo.

Todavía es posible, por cierto, poner el código de búsqueda de subconjuntos en la clase Acl; sin embargo, creo que sería mejor mantener la clase pequeña y enfocada (porque creo que la lectura del código en esa clase también es muy importante).

+0

¿Te importaría explicar esto un poco más? – Xeoncross

+0

@Xeoncross: seguro, ¿qué es lo que no entiendes? – Rijk

0

Por lo que yo sé de LCA se debe utilizar para comprobar los permisos generales. Los permisos basados ​​en entidades no deberían estar sujetos a ACL. Para tal tarea, veré cómo Linux/Unix administra los permisos de archivos.

  owner group all 
read  1  1  1 
write  1  0  0 
execute  1  0  0 
-------------------------------------- 
      7  4  4 

Con una implementación similar, los permisos de búsqueda y comprobación son fáciles, pero debe agregar una capa más a su aplicación.

edición: también esta arquitectura va a respetar el principio de responsabilidad única por lo que comprobar "si se permite al usuario abrir una página" es diferente de "lo que el usuario podrá ver en la página"

+0

Pero eso es un sistema de permisos, solo tienes como ver propietario, grupo y todas las entidades, y una parte importante de esos permisos es tener un propietario. Esto es ACL, asigna usuarios y grupos especificados a algunas acciones y que heredan reglas y reglas de grupo. –

+0

No veo la diferencia entre un "archivo" y un "objeto de actividad": ambos son "entidades" ¿no?Y un usuario puede tener un conjunto de permisos en la entidad, como 'ver', 'editar', 'eliminar' o 'leer', 'escribir', 'ejecutar' en el caso de Linux. La diferencia entre mi sistema y Linux es que mis permisos se derivan del contexto en lugar de los códigos rígidos por entidad. – Rijk

0

Eso parece ser más como un control de acceso basado en roles o RBAC, que una lista de control de acceso ACL, porque está otorgando permisos al usuario en el objeto depende de qué rol tenga, si están en el grupo, la lista de colaboración o es el propietario, pero usted no está almacenar como una función, por lo que no puede ser un RBAC, pero no está almacenando permisos porque lo está asumiendo, por lo que no puede ser una ACL.

Por lo tanto, si desea consultar un grupo de objetos con el permiso que está asumiendo, obviamente debe calcular primero los permisos asignados para obtenerlos.

Luego puede calcular eso en una función de procedimiento almacenado/udf si desea en el db no buscar todo, o hacer una tabla/lista de ACL, o un permiso de función vinculado a los objetos para los que desea otorgarles permisos.

la esperanza que esto sea útil, buena pregunta que frito un poco mi cerebro, pero ahora tengo que hacer algo similar .. tienen un buen día

+0

¡Gracias por tu comentario! Revisé RBAC, pero parece que no se ajusta a mi caso. Wikipedia afirma que "RBAC ** no es ** un modelo para asignar autorizaciones dinámicamente" - Creo que asignar aquí dinámicamente es lo que trato de hacer aquí. – Rijk

+0

El punto que trato de decir es que RBAC es una entidad de control de acceso centralizada, y para obtener una concesión a un objeto que necesita solicitar a esta entidad para el permiso. Por otro lado, ACL tiene una lista vinculada o en el objeto, y la API pregunta si la ACL del objeto otorga acceso al usuario. Si desea asignar dinámicamente sin obtener todo desde db, su única solución es un procedimiento de Función UDF/Almacenado, si tiene dudas sobre cómo escribirlo, pregúntelo. –