Gestión de ACL
Instalación
Instale el módulo Ubiquity-acl desde el símbolo del sistema o desde Webtools (parte Composer).
composer require phpmv/ubiquity-acl
A continuación, active la visualización de la parte Acl en el Webtools:
Interfaz ACL en webtools:
Normas Acl
Las ACL se utilizan para definir el acceso a una aplicación Ubiquity. Se definen de acuerdo con los siguientes principios:
- Una aplicación Ubiquity se compone de :
Recursos (posiblemente controladores, o acciones de estos controladores)
Roles, posiblemente asignados a usuarios. Cada Rol puede heredar roles padre.
Permisos, que corresponden a un derecho a hacer. Cada permiso tiene un nivel (representado por un valor entero).
- Normas adicionales:
Un AclElement (Allow) concede Permiso a un Rol sobre un Recurso.
Cada rol hereda autorizaciones de sus padres, además de las suyas propias.
Si un rol tiene un determinado nivel de permiso de acceso sobre un recurso, también tendrá todos los permisos de un nivel inferior sobre ese recurso.
La asociación de un recurso y un permiso a un controlador o a una acción de controlador define un elemento map.
- Consejos para poner nombres:
Rol, en mayúsculas, empezando por una arroba (@USER, @ADMIN, @ALL…).
Permisos, en mayúsculas, nombrados con un verbo (READ, WRITE, OPEN…).
Recurso, con mayúscula inicial (Products, Customers…)
Inicio de ACL
El servicio AclManager puede iniciarse directamente desde la interfaz webtools, en la parte Security.
El servicio se inicia en el archivo
services.php
.
\Ubiquity\security\acl\AclManager::startWithCacheProvider();
ACLCacheProvider
Este proveedor predeterminado permite gestionar ACLs definidas mediante atributos o anotaciones.
AclController
Un AclController permite la gestión automática del acceso basado en ACLs a sus propios recursos.
Es posible crearlas automáticamente desde webtools.
Pero es sólo un controlador básico, utilizando la característica AclControllerTrait.
Este controlador sólo va a redefinir el método _getRole
, para que devuelva el rol del usuario activo, por ejemplo.
<?php
namespace controllers;
use Ubiquity\controllers\Controller;
use Ubiquity\security\acl\controllers\AclControllerTrait;
use Ubiquity\attributes\items\acl\Allow;
class BaseAclController extends Controller {
use AclControllerTrait;
#[Allow('@ME')]
public function index() {
$this->loadView("BaseAclController/index.html");
}
public function _getRole() {
$_GET['role']??'@ME';//Just for testing: logically, this is the active user's role
}
/**
* {@inheritdoc}
* @see \Ubiquity\controllers\Controller::onInvalidControl()
*/
public function onInvalidControl() {
echo $this->_getRole() . ' is not allowed!';
}
}
- Se ha concedido autorización para el recurso:
Sin especificar el recurso, las acciones del controlador se definen como un recurso.
Sin especificar el permiso, se utiliza el permiso
ALL
.
Y esta asociación está presente en el mapa de Acls:
AclController con autenticación
Nota
El uso tanto de WithAuthTrait
como de AclControllerTrait
requiere eliminar la ambigüedad sobre el método isValid
.
class BaseAclController extends Controller {
use AclControllerTrait,WithAuthTrait{
WithAuthTrait::isValid insteadof AclControllerTrait;
AclControllerTrait::isValid as isValidAcl;
}
public function isValid($action){
return parent::isValid($action)&& $this->isValidAcl($action);
}
}
Permitir con función, recurso y permiso
Permitir sin creación previa:
@USER
puede acceder al recurso Foo
con permiso READ
.
use Ubiquity\attributes\items\acl\Allow;
class BaseAclController extends Controller {
use AclControllerTrait;
...
#[Allow('@USER','Foo', 'READ')]
public function foo(){
echo 'foo page allowed for @USER and @ME';
}
}
Nota
El rol, el recurso y el permiso se crean automáticamente en cuanto se invocan con Allow
.
Permitir con creación explícita:
use Ubiquity\attributes\items\acl\Allow;
use Ubiquity\attributes\items\acl\Permission;
class BaseAclController extends Controller {
use AclControllerTrait;
...
#[Permission('READ',500)]
#[Allow('@USER','Foo', 'READ')]
public function foo(){
echo 'foo page allowed for @USER and @ME';
}
}
Añadir ACL en tiempo de ejecución
Ya sea en un controlador o en un servicio, es posible añadir Roles, Recursos, Permisos y Autorizaciones en tiempo de ejecución:
Por ejemplo: Añadir un rol @USER
que herede de @GUEST
.
use Ubiquity\security\acl\AclManager;
AclManager::addRole('@GUEST');
AclManager::addRole('@USER',['@GUEST']);
Definición de ACL con base de datos
Las ACLs definidas en la base de datos son adicionales a las ACLs definidas mediante anotaciones o atributos.
Inicialización
La inicialización permite crear las tablas asociadas a las ACLs (Role, Resource, Permission, AclElement). Debe realizarse una sola vez, y únicamente en modo dev.
Para colocar por ejemplo en el archivo app/config/bootstrap.php
:
use Ubiquity\controllers\Startup;
use Ubiquity\security\acl\AclManager;
$config=Startup::$config;
AclManager::initializeDAOProvider($config, 'default');
Comenzando
En el archivo app/config/services.php
:
use Ubiquity\security\acl\AclManager;
use Ubiquity\security\acl\persistence\AclCacheProvider;
use Ubiquity\security\acl\persistence\AclDAOProvider;
use Ubiquity\orm\DAO;
DAO::start();//Optional, to use only if dbOffset is not default
AclManager::start();
AclManager::initFromProviders([
new AclCacheProvider(), new AclDAOProvider($config)
]);
Estrategias para definir ACLs
Con pocos recursos:
Definición de autorizaciones para cada acción o grupo de acciones del controlador:
Los recursos corresponden lógicamente a los controladores, y los permisos a las acciones. Pero esta regla puede no respetarse, y una acción puede definirse como un recurso, según sea necesario.
La única regla obligatoria es que un par Controlador/acción sólo puede corresponder a un par Recurso/permiso (no necesariamente único).
namespace controllers;
use Ubiquity\controllers\Controller;
use Ubiquity\security\acl\controllers\AclControllerTrait;
use Ubiquity\attributes\items\acl\Permission;
use Ubiquity\attributes\items\acl\Resource;
#[Resource('Foo')]
#[Allow('@ADMIN')]
class FooController extends Controller {
use AclControllerTrait;
#[Allow('@NONE')]
public function index() {
echo 'index';
}
#[Allow('@USER')]
public function read() {
echo 'read';
}
#[Allow('@USER')]
public function write() {
echo 'write';
}
public function admin() {
echo 'admin';
}
public function _getRole() {
return $_GET['role']??'@NONE';
}
/**
* {@inheritdoc}
* @see \Ubiquity\controllers\Controller::onInvalidControl()
*/
public function onInvalidControl() {
echo $this->_getRole() . ' is not allowed!';
}
}
Con más recursos:
namespace controllers;
use Ubiquity\controllers\Controller;
use Ubiquity\security\acl\controllers\AclControllerTrait;
use Ubiquity\attributes\items\acl\Permission;
use Ubiquity\attributes\items\acl\Resource;
#[Resource('Foo')]
class FooController extends Controller {
use AclControllerTrait;
#[Permission('INDEX',1)]
public function index() {
echo 'index';
}
#[Permission('READ',2)]
public function read() {
echo 'read';
}
#[Permission('WRITE',3)]
public function write() {
echo 'write';
}
#[Permission('ADMIN',10)]
public function admin() {
echo 'admin';
}
public function _getRole() {
return $_GET['role']??'NONE';
}
/**
* {@inheritdoc}
* @see \Ubiquity\controllers\Controller::onInvalidControl()
*/
public function onInvalidControl() {
echo $this->_getRole() . ' is not allowed!';
}
}