Commit 2b13a20f authored by Laurent Lécluse's avatar Laurent Lécluse
Browse files

Intégration de la gestion des privilèges et des droits.

parent 87b6f3a7
......@@ -2,6 +2,7 @@
namespace UnicaenAuth;
use UnicaenAuth\Guard\PrivilegeController;
use Zend\ModuleManager\Feature\AutoloaderProviderInterface;
use Zend\ModuleManager\Feature\ConfigProviderInterface;
use Zend\ModuleManager\Feature\ServiceProviderInterface;
......@@ -23,6 +24,8 @@ class Module implements ConfigProviderInterface, ServiceProviderInterface
return include __DIR__ . '/config/module.config.php';
}
/**
*
* @return array
......@@ -42,26 +45,30 @@ class Module implements ConfigProviderInterface, ServiceProviderInterface
];
}
/**
* This method is called once the MVC bootstrapping is complete,
* after the "loadModule.post" event, once $application->bootstrap() is called.
*
* @param EventInterface $e
*
* @see BootstrapListenerInterface
*/
public function onBootstrap(\Zend\EventManager\EventInterface $e) /* @var \Zend\Mvc\MvcEvent $e */
public function onBootstrap(\Zend\EventManager\EventInterface $e)
/* @var \Zend\Mvc\MvcEvent $e */
{
$application = $e->getApplication();
/* @var $services \Zend\ServiceManager\ServiceManager */
$services = $application->getServiceManager();
$services = $application->getServiceManager();
// transmission des ACL aux aides de vue de navigation
try {
$authorizeService = $services->get('BjyAuthorize\Service\Authorize'); /* @var $authorizeService \BjyAuthorize\Service\Authorize */
$authorizeService = $services->get('BjyAuthorize\Service\Authorize');
/* @var $authorizeService \BjyAuthorize\Service\Authorize */
\Zend\View\Helper\Navigation::setDefaultAcl($authorizeService->getAcl());
\Zend\View\Helper\Navigation::setDefaultRole($authorizeService->getIdentity());
}
catch (\Zend\ServiceManager\Exception\ServiceNotFoundException $snfe) {
} catch (\Zend\ServiceManager\Exception\ServiceNotFoundException $snfe) {
// pas de module BjyAuthorize : pas d'ACL
}
......@@ -75,21 +82,21 @@ class Module implements ConfigProviderInterface, ServiceProviderInterface
$router->addRoutes([
// remplace les routes existantes (cf. config du module)
'zfcuser' => [
'type' => 'Literal',
'priority' => 1000,
'options' => [
'route' => '/auth',
'type' => 'Literal',
'priority' => 1000,
'options' => [
'route' => '/auth',
'defaults' => [
'controller' => 'zfcuser',
'action' => 'index',
],
],
'may_terminate' => true,
'child_routes' => [
'login' => [
'type' => 'Literal',
'child_routes' => [
'login' => [
'type' => 'Literal',
'options' => [
'route' => '/connexion',
'route' => '/connexion',
'defaults' => [
'controller' => 'zfcuser',
'action' => 'authenticate', // zappe l'action 'login'
......@@ -97,9 +104,9 @@ class Module implements ConfigProviderInterface, ServiceProviderInterface
],
],
'logout' => [
'type' => 'Literal',
'type' => 'Literal',
'options' => [
'route' => '/deconnexion',
'route' => '/deconnexion',
'defaults' => [
'controller' => 'zfcuser',
'action' => 'logout',
......@@ -107,11 +114,13 @@ class Module implements ConfigProviderInterface, ServiceProviderInterface
],
],
],
]
],
]);
}
}
/**
*
* @return array
......@@ -122,14 +131,50 @@ class Module implements ConfigProviderInterface, ServiceProviderInterface
return [
'factories' => [
// verrue pour forcer le label de l'identifiant qqsoit l'options 'auth_identity_fields'
'zfcuser_login_form' => function($sm) {
'zfcuser_login_form' => function ($sm) {
$options = $sm->get('zfcuser_module_options');
$form = new \ZfcUser\Form\Login(null, $options);
$form = new \ZfcUser\Form\Login(null, $options);
$form->setInputFilter(new \ZfcUser\Form\LoginFilter($options));
$form->get('identity')->setLabel("Username");
return $form;
},
],
];
}
}
/**
* Retourne le menu de navigation (à placer où vous voulez)!!
*
* @return array
*/
static public function getDroitsNavigation($label=null, $title=null)
{
if (!$label) $label = "Droits d'accès";
if (!$title) $title = "Gestion des droits d'accès";
return [
'label' => $label,
'title' => $title,
'route' => 'droits',
'resource' => PrivilegeController::getResourceId('UnicaenAuth\Controller\Droits','index'),
'pages' => [
'roles' => [
'label' => "Rôles",
'title' => "Gestion des rôles",
'route' => 'droits/roles',
'resource' => PrivilegeController::getResourceId('UnicaenAuth\Controller\Droits','roles'),
'withtarget' => true,
],
'privileges' => [
'label' => "Privilèges",
'title' => "Gestion des privilèges",
'route' => 'droits/privileges',
'resource' => PrivilegeController::getResourceId('UnicaenAuth\Controller\Droits','privileges'),
'withtarget' => true,
],
],
];
}
}
\ No newline at end of file
This diff is collapsed.
......@@ -16,6 +16,11 @@ $settings = [
* (i.e. créer un compte dans la table des utilisateurs).
*/
'enable_registration' => false,
/**
* Nom du gestionnaire d'entités doctrine qui sera utilisé pour accéder à la base de données des rôles,
* utilisateurs et privilèges.
*/
//'entity_manager_name' => 'doctrine.entitymanager.orm_default',
];
/**
......
......@@ -9,6 +9,7 @@ CREATE TABLE user (
UNIQUE INDEX `unique_username` (`username` ASC)
) ENGINE=InnoDB DEFAULT CHARACTER SET = utf8 COLLATE = utf8_unicode_ci;
CREATE TABLE IF NOT EXISTS `user_role` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`role_id` VARCHAR(64) NOT NULL,
......@@ -21,6 +22,7 @@ CREATE TABLE IF NOT EXISTS `user_role` (
CONSTRAINT `fk_parent_id` FOREIGN KEY (`parent_id`) REFERENCES `user_role` (`id`) ON DELETE SET NULL
) ENGINE = InnoDB DEFAULT CHARACTER SET = utf8 COLLATE = utf8_unicode_ci;
CREATE TABLE IF NOT EXISTS `user_role_linker` (
`user_id` INT(11) NOT NULL,
`role_id` INT(11) NOT NULL,
......@@ -53,6 +55,7 @@ CREATE TABLE IF NOT EXISTS privilege (
CONSTRAINT fk_categorie_id FOREIGN KEY (categorie_id) REFERENCES categorie_privilege (id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARACTER SET = utf8 COLLATE = utf8_unicode_ci;
CREATE TABLE IF NOT EXISTS role_privilege (
role_id INT(11) NOT NULL,
privilege_id INT(11) NOT NULL,
......@@ -63,8 +66,25 @@ CREATE TABLE IF NOT EXISTS role_privilege (
CONSTRAINT fk_rp_privilege_id FOREIGN KEY (privilege_id) REFERENCES privilege (id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARACTER SET = utf8 COLLATE = utf8_unicode_ci;
-- Données
INSERT INTO `user_role` (`id`, `role_id`, `is_default`, `parent_id`) VALUES
(1, 'Standard', 1, NULL),
(2, 'Gestionnaire', 0, 1),
(3, 'Super-gestionnaire', 0, 2),
(4, 'Administrateur de l''application', 0, 3);
(4, 'Administrateur', 0, 3);
INSERT INTO `categorie_privilege` (`id`, `code`, `libelle`, `ordre`) VALUES
(1, 'droit', 'Gestion des droits', 1);
INSERT INTO `privilege` (`id`, `categorie_id`, `code`, `libelle`, `ordre`) VALUES
(1, 1, 'role-visualisation', 'Rôles - Visualisation', 1),
(2, 1, 'role-edition', 'Rôles - Édition', 2),
(3, 1, 'privilege-visualisation', 'Privilèges - Visualisation', 3),
(4, 1, 'privilege-edition', 'Privilèges - Édition', 4);
INSERT INTO `role_privilege` (`role_id`, `privilege_id`) VALUES
(4, 1),
(4, 2),
(4, 3),
(4, 4);
\ No newline at end of file
CREATE TABLE "USER"
CREATE TABLE USER
( "ID" NUMBER(*,0) NOT NULL ENABLE,
"USERNAME" VARCHAR2(255 CHAR),
"EMAIL" VARCHAR2(255 CHAR),
......@@ -8,7 +8,7 @@ CREATE TABLE "USER"
CONSTRAINT "USER_USERNAME_UN" UNIQUE ("USERNAME")
);
CREATE TABLE "USER_ROLE"
CREATE TABLE USER_ROLE
( "ID" NUMBER(*,0) NOT NULL ENABLE,
"ROLE_ID" VARCHAR2(64 CHAR) NOT NULL ENABLE,
"IS_DEFAULT" NUMBER(38,0) NOT NULL ENABLE,
......@@ -19,7 +19,7 @@ CREATE TABLE "USER_ROLE"
);
CREATE INDEX "USER_ROLE_PARENT__IDX" ON "USER_ROLE" ("PARENT_ID");
CREATE TABLE "OSE"."USER_ROLE_LINKER"
CREATE TABLE USER_ROLE_LINKER
( "USER_ID" NUMBER(*,0) NOT NULL ENABLE,
"ROLE_ID" NUMBER(*,0) NOT NULL ENABLE,
CONSTRAINT "USER_ROLE_LINKER_PK" PRIMARY KEY ("USER_ID", "ROLE_ID")
......@@ -27,4 +27,3 @@ CREATE TABLE "OSE"."USER_ROLE_LINKER"
CONSTRAINT "USER_ROLE_USER_ROLE_FK" FOREIGN KEY ("ROLE_ID") REFERENCES "USER_ROLE" ("ID") ON DELETE CASCADE ENABLE
);
CREATE INDEX "USER_ROLE_LINKER_ROLE_IDX" ON "USER_ROLE_LINKER" ("ROLE_ID");
CREATE INDEX "USER_ROLE_LINKER_USER_IDX" ON "USER_ROLE_LINKER" ("USER_ID");
\ No newline at end of file
<?php
namespace UnicaenAuth\Assertion;
use Zend\Mvc\MvcEvent;
use Zend\Permissions\Acl\Acl;
use Zend\Permissions\Acl\Assertion\AssertionInterface;
use Zend\Permissions\Acl\Resource\ResourceInterface;
use Zend\Permissions\Acl\Role\RoleInterface;
use Zend\ServiceManager\ServiceLocatorAwareInterface;
use Zend\ServiceManager\ServiceLocatorAwareTrait;
/**
* Description of AbstractAssertion
*
* @author Laurent LÉCLUSE <laurent.lecluse at unicaen.fr>
*/
abstract class AbstractAssertion implements AssertionInterface, ServiceLocatorAwareInterface
{
use ServiceLocatorAwareTrait;
/**
* !!!! Pour éviter l'erreur "Serialization of 'Closure' is not allowed"... !!!!
*
* @return array
*/
public function __sleep()
{
return [];
}
/**
* Returns true if and only if the assertion conditions are met
*
* This method is passed the ACL, Role, Resource, and privilege to which the authorization query applies. If the
* $role, $this->resource, or $privilege parameters are null, it means that the query applies to all Roles, Resources, or
* privileges, respectively.
*
* @param Acl $acl
* @param RoleInterface $role
* @param ResourceInterface $resource
* @param string $privilege
*
* @return bool
*/
public final function assert(Acl $acl, RoleInterface $role = null, ResourceInterface $resource = null, $privilege = null)
{
switch (true) {
case $this->detectPrivilege($resource):
return $this->assertPrivilege($acl, $role, ltrim(strstr($resource, '/'), '/'), $privilege);
case $this->detectController($resource):
$resource = (string)$resource;
$spos = strpos($resource, '/') + 1;
$dpos = strrpos($resource, ':') + 1;
$controller = substr($resource, $spos, $dpos - $spos - 1);
$action = substr($resource, $dpos);
return $this->assertController($acl, $role, $controller, $action, $privilege);
case $this->detectEntity($resource):
return $this->assertEntity($acl, $role, $resource, $privilege);
default:
return $this->assertOther($acl, $role, $resource, $privilege);
}
}
/**
*
* @param string $resource
*
* @return boolean
*/
private function detectPrivilege($resource = null)
{
if ($resource instanceof ResourceInterface) $resource = $resource->getResourceId();
return is_string($resource) && 0 === strpos($resource, 'privilege/');
}
/**
*
* @param Acl $acl
* @param RoleInterface $role
* @param string $privilege
* @param string $subPrivilege
*
* @return boolean
*/
protected function assertPrivilege(Acl $acl, RoleInterface $role = null, $privilege = null, $subPrivilege = null)
{
return true;
}
/**
*
* @param string $resource
*
* @return boolean
*/
private function detectController($resource = null)
{
if ($resource instanceof ResourceInterface) $resource = $resource->getResourceId();
return 0 === strpos($resource, 'controller/');
}
/**
*
* @param Acl $acl
* @param RoleInterface $role
* @param string $controller
* @param string $action
* @param string $privilege
*
* @return boolean
*/
protected function assertController(Acl $acl, RoleInterface $role = null, $controller = null, $action = null, $privilege = null)
{
return true;
}
/**
*
* @param string $resource
*
* @return boolean
*/
private function detectEntity($resource = null)
{
return
is_object($resource)
&& method_exists($resource, 'getId');
}
/**
*
* @param Acl $acl
* @param RoleInterface $role
* @param ResourceInterface $entity
* @param string $privilege
*
* @return boolean
*/
protected function assertEntity(Acl $acl, RoleInterface $role = null, ResourceInterface $entity = null, $privilege = null)
{
return true;
}
/**
*
* @param Acl $acl
* @param RoleInterface $role
* @param ResourceInterface $entity
* @param string $privilege
*
* @return boolean
*/
protected function assertOther(Acl $acl, RoleInterface $role = null, ResourceInterface $entity = null, $privilege = null)
{
return true;
}
/**
*
* @return MvcEvent
*/
protected function getMvcEvent()
{
$application = $this->getServiceLocator()->get('Application');
return $application->getMvcEvent();
}
}
\ No newline at end of file
<?php
namespace UnicaenAuth\Controller;
use UnicaenAuth\Entity\Db\Privilege;
use UnicaenAuth\Entity\Db\Role;
use UnicaenAuth\Form\Droits\Traits\RoleFormAwareTrait;
use UnicaenAuth\Service\Traits\PrivilegeServiceAwareTrait;
use UnicaenAuth\Service\Traits\RoleServiceAwareTrait;
use Zend\Form\Form;
use Zend\Mvc\Controller\AbstractActionController;
use Zend\View\Model\ViewModel;
/**
* Description of DroitsController
*
*
* @author Laurent LÉCLUSE <laurent.lecluse at unicaen.fr>
*/
class DroitsController extends AbstractActionController
{
use RoleServiceAwareTrait;
use RoleFormAwareTrait;
use PrivilegeServiceAwareTrait;
/**
*
* @return type
*/
public function indexAction()
{
return [];
}
public function rolesAction()
{
$roles = $this->getServiceRole()->getList();
return compact('roles');
}
public function roleEditionAction()
{
$roleId = $this->params()->fromRoute('role');
$role = $this->getServiceRole()->get($roleId);
$errors = [];
$form = $this->getFormDroitsRole();
if (empty($role)) {
$title = 'Création d\'un nouveau rôle';
$role = $this->getServiceRole()->newEntity();
$form->setObject($role);
} else {
$title = 'Édition du rôle';
$form->bind($role);
}
$form->setAttribute('action', $this->url()->fromRoute(null, [], [], true));
$request = $this->getRequest();
if ($request->isPost()) {
$form->setData($request->getPost());
if ($form->isValid()) {
try {
$this->getServiceRole()->save($role);
$form->get('id')->setValue($role->getId()); // transmet le nouvel ID
} catch (\Exception $e) {
$errors[] = $e->getMessage();
}
}
}
return compact('form', 'title', 'errors');
}
public function roleSuppressionAction()
{
$roleId = $this->params()->fromRoute('role');
$role = $this->getServiceRole()->get($roleId);
$title = "Suppression du rôle";
$form = $this->getFormSupprimer();
$errors = [];
if ($this->getRequest()->isPost()) {
try {
$this->getServiceRole()->delete($role);
} catch (\Exception $e) {
$errors[] = $e->getMessage();
}
}
return compact('role', 'title', 'form', 'errors');
}
public function privilegesAction()
{
$ps = $this->getServicePrivilege()->getList();
$privileges = [];
foreach ($ps as $privilege) {
$categorie = $privilege->getCategorie();
if (!isset($privileges[$categorie->getCode()])) {
$privileges[$categorie->getCode()] = [
'categorie' => $categorie,
'privileges' => [],
];
}
$privileges[$categorie->getCode()]['privileges'][] = $privilege;
}
$roles = $this->getServiceRole()->getList();
return compact('privileges', 'roles');
}
public function privilegesModifierAction()
{
$roleId = $this->params()->fromPost('role');
$role = $this->getServiceRole()->get($roleId);
$privilegeId = $this->params()->fromPost('privilege');
$privilege = $this->getServicePrivilege()->get($privilegeId);
$action = $this->params()->fromPost('action');
switch ($action) {
case 'accorder':
$this->getServicePrivilege()->addRole($privilege,$role);
break;
case 'refuser':
$this->getServicePrivilege()->removeRole($privilege,$role);
break;
}
$viewModel = new ViewModel();
$viewModel->setVariables(compact('role', 'privilege'))
->setTerminal(true);
return $viewModel;
}
public function getFormSupprimer()
{
$form = new Form();
$form->add([
'name' => 'id',