<?php
/**
* KumbiaPHP web & app Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://wiki.kumbiaphp.com/Licencia
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to hide@address.com so we can send you a copy immediately.
*
* Cada lista ACL contiene una lista de Roles, unos resources y unas acciones de
* acceso;
*
* @category Kumbia
* @package Acl
* @copyright Copyright (c) 2005-2009 Kumbia Team (http://www.kumbiaphp.com)
* @license http://wiki.kumbiaphp.com/Licencia New BSD License
*/
/**
* @see AclRole
*/
include CORE_PATH . 'libs/acl/role/role.php';
/**
* @see AclResource
*/
include CORE_PATH . 'libs/acl/resource/resource.php';
/**
* Listas ACL (Access Control List)
*
* La Lista de Control de Acceso o ACLs (del ingles, Access Control List)
* es un concepto de seguridad informatica usado para fomentar la separacion
* de privilegios. Es una forma de determinar los permisos de acceso apropiados
* a un determinado objeto, dependiendo de ciertos aspectos del proceso
* que hace el pedido.
*
* Cada lista ACL contiene una lista de Roles, unos resources y unas acciones de
* acceso;
*
* $roles = Lista de Objetos Acl_Role de Roles de la Lista
* $resources = Lista de Objetos Acl_Resource que van a ser controlados
* $access = Contiene la lista de acceso
* $role_inherits = Contiene la lista de roles que son heradados por otros
* $resource_names = Nombres de Resources
* $roles_names = Nombres de Resources
*
*/
class Acl {
/**
* Nombres de Roles en la lista ACL
*
* @var array
*/
private $roles_names = array();
/**
* Objetos Roles en lista ACL
*
* @var array
*/
private $roles = array();
/**
* Objetos Resources en la lista ACL
*
* @var array
*/
private $resources = array();
/**
* Permisos de la Lista de Acceso
*
* @var array
*/
public $access = array();
/**
* Herencia entre Roles
*
* @var array
*/
private $role_inherits = array();
/**
* Array de Nombres de Recursos
*
* @var array
*/
private $resources_names = array('*');
/**
* Lista ACL de permisos
*
* @var array
*/
private $access_list = array('*' => array('*'));
/**
* Agrega un Rol a la Lista ACL
*
* $roleObject = Objeto de la clase AclRole para agregar a la lista
* $access_inherits = Nombre del Role del cual hereda permisos ó array del grupo
* de perfiles del cual hereda permisos
*
* Ej:
* <code>$acl->add_role(new Acl_Role('administrador'), 'consultor');</code>
*
* @param string $roleObject
* @return boolean
*/
public function add_role(AclRole $roleObject, $access_inherits='') {
if(in_array($roleObject->name, $this->roles_names)) {
return false;
}
$this->roles[] = $roleObject;
$this->roles_names[] = $roleObject->name;
$this->access[$roleObject->name]['*']['*'] = 'A';
if($access_inherits) {
$this->add_inherit($roleObject->name, $access_inherits);
}
}
/**
* Hace que un rol herede los accesos de otro rol
*
* @param string $role
* @param string $role_to_inherit
*/
public function add_inherit($role, $role_to_inherit) {
if(!in_array($role, $this->roles_names)) {
return false;
}
if($role_to_inherit!='') {
if(is_array($role_to_inherit)) {
foreach($role_to_inherit as $rol_in) {
if($rol_in==$role) {
return false;
}
if(!in_array($rol_in, $this->roles_names)) {
throw new KumbiaException("El Rol '{$rol_in}' no existe en la lista");
return false;
}
$this->role_inherits[$role][] = $role_in;
}
$this->rebuild_access_list();
} else {
if($role_to_inherit==$role) {
return false;
}
if(!in_array($role_to_inherit, $this->roles_names)) {
throw new KumbiaException("El Rol '{$role_to_inherit}' no existe en la lista");
return false;
}
$this->role_inherits[$role][] = $role_to_inherit;
$this->rebuild_access_list();
}
} else {
throw new KumbiaException("Debe especificar un rol a heredar en Acl::add_inherit");
return false;
}
}
/**
*
* Verifica si un rol existe en la lista o no
*
* @param string $role_name
* @return boolean
*/
public function is_role($role_name) {
return in_array($role_name, $this->roles_names);
}
/**
*
* Verifica si un resource existe en la lista o no
*
* @param string $resource_name
* @return boolean
*/
public function is_resource($resource_name) {
return in_array($resource_name, $this->resources_names);
}
/**
* Agrega un a la Lista ACL
*
* Resource_name puede ser el nombre de un objeto concreo, por ejemplo
* consulta, buscar, insertar, valida etc � una lista de ellos
*
* Ej:
* <code>
* //Agregar un resource a la lista:
* $acl->add_resource(new AclResource('clientes'), 'consulta');
*
* //Agregar Varios resources a la lista:
* $acl->add_resource(new AclResource('clientes'), 'consulta', 'buscar', 'insertar');
* </code>
*
* @param AclResource $resource
* @return boolean
*/
public function add_resource(Acl_Resource $resource) {
if(!in_array($resource->name, $this->resources)) {
$this->resources[] = $resource;
$this->access_list[$resource->name] = array();
$this->resources_names[] = $resource->name;
}
if(func_num_args()>1) {
$access_list = func_get_args();
unset($access_list[0]);
$this->add_resource_access($resource->name, $access_list);
}
}
/**
* Agrega accesos a un Resource
*
* @param $resource
* @param $access_list
*/
public function add_resource_access($resource, $access_list) {
if(is_array($access_list)) {
foreach($access_list as $access_name) {
if(!in_array($access_name, $this->access_list[$resource])) {
$this->access_list[$resource][] = $access_name;
}
}
} else {
if(!in_array($access_list, $this->access_list[$resource])) {
$this->access_list[$resource][] = $access_list;
}
}
}
/**
* Elimina un acceso del resorce
*
* @param string $resource
* @param mixed $access_list
*/
public function drop_resource_access($resource, $access_list) {
if(is_array($access_list)) {
foreach($access_list as $access_name) {
if(in_array($access_name, $this->access_list[$resource])) {
foreach($this->access_list[$resource] as $i => $access) {
if($access==$access_name) {
unset($this->access_list[$resource][$i]);
}
}
}
}
} else {
if(in_array($access_list, $this->access_list[$resource])) {
foreach($this->access_list[$resource] as $i => $access) {
if($access==$access_list) {
unset($this->access_list[$resource][$i]);
}
}
}
}
$this->rebuild_access_list();
}
/**
* Agrega un acceso de la lista de resources a un rol
*
* Utilizar '*' como comod�n
*
* Ej:
* <code>
* //Acceso para invitados a consultar en clientes
* $acl->allow('invitados', 'clientes', 'consulta');
*
* //Acceso para invitados a consultar e insertar en clientes
* $acl->allow('invitados', 'clientes', array('consulta', 'insertar'));
*
* //Acceso para cualquiera a visualizar en productos
* $acl->allow('*', 'productos', 'visualiza');
*
* //Acceso para cualquiera a visualizar en cualquier resource
* $acl->allow('*', '*', 'visualiza');
* </code>
*
* @param string $role
* @param string $resource
* @param mixed $access
*/
public function allow($role, $resource, $access) {
if(!in_array($role, $this->roles_names)) {
throw new KumbiaException("No existe el rol '$role' en la lista");
return;
}
if(!in_array($resource, $this->resources_names)) {
throw new KumbiaException("No existe el resource '$resource' en la lista");
return;
}
if(is_array($access)) {
foreach($access as $acc) {
if(!in_array($acc, $this->access_list[$resource])) {
throw new KumbiaException("No existe el acceso '$acc' en el resource '$resource' de la lista");
return false;
}
}
foreach($access as $acc) {
$this->access[$role][$resource][$acc] = 'A';
}
} else {
if(!in_array($access, $this->access_list[$resource])) {
throw new KumbiaException("No existe el acceso '$acc' en el resource '$resource' de la lista");
return false;
}
$this->access[$role][$resource][$access] = 'A';
$this->rebuild_access_list();
}
}
/**
* Denegar un acceso de la lista de resources a un rol
*
* Utilizar '*' como comod�n
*
* Ej:
* <code>
* //Denega acceso para invitados a consultar en clientes
* $acl->deny('invitados', 'clientes', 'consulta');
*
* //Denega acceso para invitados a consultar e insertar en clientes
* $acl->deny('invitados', 'clientes', array('consulta', 'insertar'));
*
* //Denega acceso para cualquiera a visualizar en productos
* $acl->deny('*', 'productos', 'visualiza');
*
* //Denega acceso para cualquiera a visualizar en cualquier resource
* $acl->deny('*', '*', 'visualiza');
* </code>
*
* @param string $role
* @param string $resource
* @param mixed $access
*/
public function deny($role, $resource, $access) {
if(!in_array($role, $this->roles_names)) {
throw new KumbiaException("No existe el rol '$role' en la lista");
return;
}
if(!in_array($resource, $this->resources_names)) {
throw new KumbiaException("No existe el resource '$resource' en la lista");
return;
}
if(is_array($access)) {
foreach($access as $acc) {
if(!in_array($acc, $this->access_list[$resource])) {
throw new KumbiaException("No existe el acceso '$access' en el resource '$resource' de la lista");
return false;
}
}
foreach($access as $acc) {
$this->access[$role][$resource][$acc] = 'D';
}
} else {
if(!in_array($access, $this->access_list[$resource])) {
throw new KumbiaException("No existe el acceso '$access' en el resource '$resource' de la lista");
return false;
}
$this->access[$role][$resource][$access] = 'D';
$this->rebuild_access_list();
}
}
/**
* Devuelve true si un $role, tiene acceso en un resource
*
* <code>
* //Andres tiene acceso a insertar en el resource productos
* $acl->is_allowed('andres', 'productos', 'insertar');
*
* //Invitado tiene acceso a editar en cualquier resource?
* $acl->is_allowed('invitado', '*', 'editar');
*
* //Invitado tiene acceso a editar en cualquier resource?
* $acl->is_allowed('invitado', '*', 'editar');
* </code>
*
* @param string $role
* @param string $resource
* @param mixed $access
* @return boolean
*/
public function is_allowed($role, $resource, $access_list) {
if(!in_array($role, $this->roles_names)) {
throw new KumbiaException("El rol '$role' no existe en la lista en acl::is_allowed");
return false;
}
if(!in_array($resource, $this->resources_names)) {
throw new KumbiaException("El resource '$resource' no existe en la lista en acl::is_allowed");
return false;
}
if(is_array($access_list)) {
foreach ($access_list as $access) {
if(!in_array($access, $this->access_list[$resource])) {
throw new KumbiaException("No existe en acceso '$access' en el resource '$resource' en acl::is_allowed");
return false;
}
}
} else {
if(!in_array($access_list, $this->access_list[$resource])) {
throw new KumbiaException("No existe en acceso '$access_list' en el resource '$resource' en acl::is_allowed");
return false;
}
}
/*foreach($this->access[$role] as ){
}*/
}
/**
* Reconstruye la lista de accesos a partir de las herencias
* y accesos permitidos y denegados
*
* @access private
*/
private function rebuild_access_list() {
for($i=0;$i<=ceil(count($this->roles)*count($this->roles)/2);$i++) {
foreach($this->roles_names as $role) {
if(isset($this->role_inherits[$role])) {
foreach($this->role_inherits[$role] as $role_inherit) {
if(isset($this->access[$role_inherit])) {
foreach($this->access[$role_inherit] as $resource_name => $access) {
foreach ($access as $access_name => $value) {
if(!in_array($access_name, $this->access_list[$resource_name])) {
unset($this->access[$role_inherit][$resource_name][$access_name]);
} else {
if(!isset($this->access[$role][$resource_name][$access_name])) {
$this->access[$role][$resource_name][$access_name] = $value;
}
}
}
}
}
}
}
}
}
}
}