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,14 +45,18 @@ 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 */
......@@ -57,11 +64,11 @@ class Module implements ConfigProviderInterface, ServiceProviderInterface
// 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
}
......@@ -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->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
<?php
use UnicaenAuth\Provider\Privilege\Privileges;
$settings = [
'entity_manager_name' => 'doctrine.entitymanager.orm_default', // nom du gestionnaire d'entités à utiliser
/**
* Fournisseurs d'identité.
*/
'identity_providers' => [
300 => 'UnicaenAuth\Provider\Identity\Basic', // en 1er
200 => 'UnicaenAuth\Provider\Identity\Db', // en 2e
100 => 'UnicaenAuth\Provider\Identity\Ldap', // en 3e
100 => 'UnicaenAuth\Provider\Identity\Ldap', // en 3e @deprecated
],
];
$zfcuserSettings = [
return [
'zfcuser' => [
/**
* Enable registration
* Allows users to register through the website.
......@@ -69,9 +75,8 @@ $zfcuserSettings = [
'user_entity_class' => 'UnicaenAuth\Entity\Db\User',
// telling ZfcUserDoctrineORM to skip the entities it defines
'enable_default_entities' => false,
];
$bjyauthorize = [
],
'bjyauthorize' => [
/* this module uses a meta-role that inherits from any roles that should
* be applied to the active user. the identity provider tells us which
* roles the "identity role" should inherit from.
......@@ -101,10 +106,7 @@ $bjyauthorize = [
* NB: si le rôle par défaut 'guest' est fourni ici, il ne sera pas ajouté en double dans les ACL.
* NB: si la connexion à la base échoue, ce n'est pas bloquant!
*/
'UnicaenAuth\Provider\Role\DbRole' => [
'object_manager' => 'doctrine.entitymanager.orm_default',
'role_entity_class' => 'UnicaenAuth\Entity\Db\Role',
],
'UnicaenAuth\Provider\Role\DbRole' => [],
/**
* Fournit le rôle correspondant à l'identifiant de connexion de l'utilisateur.
* Cela est utile lorsque l'on veut gérer les habilitations d'un utilisateur unique
......@@ -113,6 +115,14 @@ $bjyauthorize = [
'UnicaenAuth\Provider\Role\Username' => [],
],
'rule_providers' => [
//'UnicaenAuth\Provider\Rule\PrivilegeRuleProvider' => [],
],
'resource_providers' => [
'UnicaenAuth\Service\Privilege' => [],
],
// strategy service name for the strategy listener to be used when permission-related errors are detected
// 'unauthorized_strategy' => 'BjyAuthorize\View\RedirectionStrategy',
'unauthorized_strategy' => 'UnicaenAuth\View\RedirectionStrategy',
......@@ -138,12 +148,38 @@ $bjyauthorize = [
['controller' => 'UnicaenApp\Controller\Application', 'action' => 'refresh-session', 'roles' => []],
['controller' => 'UnicaenAuth\Controller\Utilisateur', 'action' => 'selectionner-profil', 'roles' => []],
],
'UnicaenAuth\Guard\PrivilegeController' => [
[
'controller' => 'UnicaenAuth\Controller\Droits',
'action' => ['index'],
'privileges' => [
Privileges::DROIT_ROLE_VISUALISATION,
Privileges::DROIT_PRIVILEGE_VISUALISATION,
],
],
[
'controller' => 'UnicaenAuth\Controller\Droits',
'action' => ['roles'],
'privileges' => [Privileges::DROIT_ROLE_VISUALISATION],
],
[
'controller' => 'UnicaenAuth\Controller\Droits',
'action' => ['privileges'],
'privileges' => [Privileges::DROIT_PRIVILEGE_VISUALISATION],
],
[
'controller' => 'UnicaenAuth\Controller\Droits',
'action' => ['role-edition', 'role-suppression'],
'privileges' => [Privileges::DROIT_ROLE_EDITION],
],
[
'controller' => 'UnicaenAuth\Controller\Droits',
'action' => ['privileges-modifier'],
'privileges' => [Privileges::DROIT_PRIVILEGE_EDITION],
],
],
],
],
];
return [
'zfcuser' => $zfcuserSettings,
'bjyauthorize' => $bjyauthorize,
'unicaen-auth' => $settings,
'doctrine' => [
'driver' => [
......@@ -170,41 +206,6 @@ return [
],
],
],
'service_manager' => [
'aliases' => [
'Zend\Authentication\AuthenticationService' => 'zfcuser_auth_service',
],
'invokables' => [
'unicaen-auth_user_service' => 'UnicaenAuth\Service\User',
'UnicaenAuth\Authentication\Storage\Db' => 'UnicaenAuth\Authentication\Storage\Db',
'UnicaenAuth\Authentication\Storage\Ldap' => 'UnicaenAuth\Authentication\Storage\Ldap',
'UnicaenAuth\View\RedirectionStrategy' => 'UnicaenAuth\View\RedirectionStrategy',
'authUserContext' => 'UnicaenAuth\Service\UserContext',
],
'abstract_factories' => [
'UnicaenAuth\Authentication\Adapter\AbstractFactory',
],
'factories' => [
'unicaen-auth_module_options' => 'UnicaenAuth\Options\ModuleOptionsFactory',
'zfcuser_auth_service' => 'UnicaenAuth\Authentication\AuthenticationServiceFactory',
'UnicaenAuth\Authentication\Storage\Chain' => 'UnicaenAuth\Authentication\Storage\ChainServiceFactory',
'UnicaenAuth\Provider\Identity\Chain' => 'UnicaenAuth\Provider\Identity\ChainServiceFactory',
'UnicaenAuth\Provider\Identity\Ldap' => 'UnicaenAuth\Provider\Identity\LdapServiceFactory',
'UnicaenAuth\Provider\Identity\Db' => 'UnicaenAuth\Provider\Identity\DbServiceFactory',
'UnicaenAuth\Provider\Identity\Basic' => 'UnicaenAuth\Provider\Identity\BasicServiceFactory',
'UnicaenAuth\Provider\Role\Config' => 'UnicaenAuth\Provider\Role\ConfigServiceFactory',
'UnicaenAuth\Provider\Role\DbRole' => 'UnicaenAuth\Provider\Role\DbRoleServiceFactory',
'UnicaenAuth\Provider\Role\Username' => 'UnicaenAuth\Provider\Role\UsernameServiceFactory',
],
'initializers' => [
'UnicaenAuth\Service\UserAwareInitializer',
],
],
'controllers' => [
'invokables' => [
'UnicaenAuth\Controller\Utilisateur' => 'UnicaenAuth\Controller\UtilisateurController',
],
],
'view_manager' => [
'template_map' => [
'error/403' => __DIR__ . '/../view/error/403.phtml',
......@@ -295,6 +296,80 @@ return [
],
],
],
'droits' => [
'type' => 'Literal',
'options' => [
'route' => '/droits',
'defaults' => [
'__NAMESPACE__' => 'UnicaenAuth\Controller',
'controller' => 'Droits',
'action' => 'index',
],
],
'may_terminate' => true,
'child_routes' => [
'roles' => [
'type' => 'Segment',
'may_terminate' => true,
'options' => [
'route' => '/roles',
'defaults' => [
'action' => 'roles',
],
],
'child_routes' => [
'edition' => [
'type' => 'Segment',
'may_terminate' => true,
'options' => [
'route' => '/edition[/:role]',
'constraints' => [
'role' => '[0-9]*',
],
'defaults' => [
'action' => 'role-edition',
],
],
],
'suppression' => [
'type' => 'Segment',
'may_terminate' => true,
'options' => [
'route' => '/suppression/:role',
'constraints' => [
'role' => '[0-9]*',
],
'defaults' => [
'action' => 'role-suppression',
],
],
],
],
],
'privileges' => [
'type' => 'Literal',
'may_terminate' => true,
'options' => [
'route' => '/privileges',
'defaults' => [
'action' => 'privileges',
],
],
'child_routes' => [
'modifier' => [
'type' => 'Segment',
'may_terminate' => true,
'options' => [
'route' => '/modifier',
'defaults' => [
'action' => 'privileges-modifier',
],
],
],
],
],
],
],
],
],
// All navigation-related configuration is collected in the 'navigation' key
......@@ -318,6 +393,57 @@ return [
],
],
],
'service_manager' => [
'aliases' => [
'Zend\Authentication\AuthenticationService' => 'zfcuser_auth_service',
'UnicaenAuth\Privilege\PrivilegeProvider' => 'UnicaenAuth\Service\Privilege',
'unicaen-auth_user_service' => 'UnicaenAuth\Service\User', // pour la compatibilité
'authUserContext' => 'UnicaenAuth\Service\UserContext', // pour la compatibilité
],
'invokables' => [
'UnicaenAuth\Authentication\Storage\Db' => 'UnicaenAuth\Authentication\Storage\Db',
'UnicaenAuth\Authentication\Storage\Ldap' => 'UnicaenAuth\Authentication\Storage\Ldap',
'UnicaenAuth\View\RedirectionStrategy' => 'UnicaenAuth\View\RedirectionStrategy',
'UnicaenAuth\Service\UserContext' => 'UnicaenAuth\Service\UserContext',
'UnicaenAuth\Service\User' => 'UnicaenAuth\Service\User',
'UnicaenAuth\Service\Privilege' => 'UnicaenAuth\Service\PrivilegeService',
'UnicaenAuth\Service\CategoriePrivilege' => 'UnicaenAuth\Service\CategoriePrivilegeService',
'UnicaenAuth\Service\Role' => 'UnicaenAuth\Service\RoleService',
],
'abstract_factories' => [
'UnicaenAuth\Authentication\Adapter\AbstractFactory',
],
'factories' => [
'unicaen-auth_module_options' => 'UnicaenAuth\Options\ModuleOptionsFactory',
'zfcuser_auth_service' => 'UnicaenAuth\Authentication\AuthenticationServiceFactory',
'UnicaenAuth\Authentication\Storage\Chain' => 'UnicaenAuth\Authentication\Storage\ChainServiceFactory',
'UnicaenAuth\Provider\Identity\Chain' => 'UnicaenAuth\Provider\Identity\ChainServiceFactory',
'UnicaenAuth\Provider\Identity\Ldap' => 'UnicaenAuth\Provider\Identity\LdapServiceFactory',
'UnicaenAuth\Provider\Identity\Db' => 'UnicaenAuth\Provider\Identity\DbServiceFactory',
'UnicaenAuth\Provider\Identity\Basic' => 'UnicaenAuth\Provider\Identity\BasicServiceFactory',
'UnicaenAuth\Provider\Role\Config' => 'UnicaenAuth\Provider\Role\ConfigServiceFactory',
'UnicaenAuth\Provider\Role\DbRole' => 'UnicaenAuth\Provider\Role\DbRoleServiceFactory',
'UnicaenAuth\Provider\Role\Username' => 'UnicaenAuth\Provider\Role\UsernameServiceFactory',
'BjyAuthorize\Service\Authorize' => 'UnicaenAuth\Service\AuthorizeServiceFactory', // surcharge!!!
],
'initializers' => [
'UnicaenAuth\Service\UserAwareInitializer',
],
],
'controllers' => [
'invokables' => [
'UnicaenAuth\Controller\Utilisateur' => 'UnicaenAuth\Controller\UtilisateurController',
'UnicaenAuth\Controller\Droits' => 'UnicaenAuth\Controller\DroitsController',
],
],
'form_elements' => [
'invokables' => [
'UnicaenAuth\Form\Droits\Role' => 'UnicaenAuth\Form\Droits\RoleForm',
],
],
'view_helpers' => [
'factories' => [
......
......@@ -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