diff --git a/Module.php b/Module.php index 42734fb2537737226c8862521c0b4c387d22a29d..f422d0eb12dafc7a8c34f6a7eb22dbe8178f32ed 100644 --- a/Module.php +++ b/Module.php @@ -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 diff --git a/config/module.config.php b/config/module.config.php index 6ad30f0423c92bb94ac59e78fc5125937a9981f2..d7d20d8c3031e7b0ba1de5521c953b83b1a0c70b 100644 --- a/config/module.config.php +++ b/config/module.config.php @@ -1,149 +1,185 @@ <?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' => [ + 'identity_providers' => [ 300 => 'UnicaenAuth\Provider\Identity\Basic', // en 1er 200 => 'UnicaenAuth\Provider\Identity\Db', // en 2e - 100 => 'UnicaenAuth\Provider\Identity\Ldap', // en 3e - ], -]; - -$zfcuserSettings = [ - /** - * Enable registration - * Allows users to register through the website. - * Accepted values: boolean true or false - */ - 'enable_registration' => true, - /** - * Modes for authentication identity match - * Specify the allowable identity modes, in the order they should be - * checked by the Authentication plugin. - * Default value: array containing 'email' - * Accepted values: array containing one or more of: email, username - */ - 'auth_identity_fields' => ['username', 'email'], - /** - * Login Redirect Route - * Upon successful login the user will be redirected to the entered route - * Default value: 'zfcuser' - * Accepted values: A valid route name within your application - */ - 'login_redirect_route' => 'home', - /** - * Logout Redirect Route - * Upon logging out the user will be redirected to the enterd route - * Default value: 'zfcuser/login' - * Accepted values: A valid route name within your application - */ - 'logout_redirect_route' => 'home', - /** - * Enable Username - * Enables username field on the registration form, and allows users to log - * in using their username OR email address. Default is false. - * Accepted values: boolean true or false - */ - 'enable_username' => false, - /** - * Enable Display Name - * Enables a display name field on the registration form, which is persisted - * in the database. Default value is false. - * Accepted values: boolean true or false - */ - 'enable_display_name' => true, - /** - * Authentication Adapters - * Specify the adapters that will be used to try and authenticate the user - * Default value: array containing 'ZfcUser\Authentication\Adapter\Db' with priority 100 - * Accepted values: array containing services that implement 'ZfcUser\Authentication\Adapter\ChainableAdapter' - */ - 'auth_adapters' => [ - 300 => 'UnicaenAuth\Authentication\Adapter\Ldap', // notifié en 1er - 200 => 'UnicaenAuth\Authentication\Adapter\Db', // ensuite (si échec d'authentification Ldap) - 100 => 'UnicaenAuth\Authentication\Adapter\Cas', // ensuite (si échec d'authentification Db) + 100 => 'UnicaenAuth\Provider\Identity\Ldap', // en 3e @deprecated ], - - // telling ZfcUser to use our own class - 'user_entity_class' => 'UnicaenAuth\Entity\Db\User', - // telling ZfcUserDoctrineORM to skip the entities it defines - 'enable_default_entities' => false, ]; -$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. - * - * for ZfcUser, this will be your default identity provider - */ - 'identity_provider' => 'UnicaenAuth\Provider\Identity\Chain', - - /* role providers simply provide a list of roles that should be inserted - * into the Zend\Acl instance. the module comes with two providers, one - * to specify roles in a config file and one to load roles using a - * Zend\Db adapter. - */ - 'role_providers' => [ +return [ + 'zfcuser' => [ /** - * 2 rôles doivent systématiquement exister dans les ACL : - * - le rôle par défaut 'guest', c'est le rôle de tout utilisateur non authentifié. - * - le rôle 'user', c'est le rôle de tout utilisateur authentifié. + * Enable registration + * Allows users to register through the website. + * Accepted values: boolean true or false */ - 'UnicaenAuth\Provider\Role\Config' => [ - 'guest' => ['name' => "Non authentifié(e)", 'selectable' => false, 'children' => [ - 'user' => ['name' => "Authentifié(e)", 'selectable' => false], - ]], - ], + 'enable_registration' => true, /** - * Fournit les rôles issus de la base de données éventuelle de l'appli. - * 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! + * Modes for authentication identity match + * Specify the allowable identity modes, in the order they should be + * checked by the Authentication plugin. + * Default value: array containing 'email' + * Accepted values: array containing one or more of: email, username */ - 'UnicaenAuth\Provider\Role\DbRole' => [ - 'object_manager' => 'doctrine.entitymanager.orm_default', - 'role_entity_class' => 'UnicaenAuth\Entity\Db\Role', - ], + 'auth_identity_fields' => ['username', 'email'], + /** + * Login Redirect Route + * Upon successful login the user will be redirected to the entered route + * Default value: 'zfcuser' + * Accepted values: A valid route name within your application + */ + 'login_redirect_route' => 'home', /** - * 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 - * sur des ressources. + * Logout Redirect Route + * Upon logging out the user will be redirected to the enterd route + * Default value: 'zfcuser/login' + * Accepted values: A valid route name within your application */ - 'UnicaenAuth\Provider\Role\Username' => [], + 'logout_redirect_route' => 'home', + /** + * Enable Username + * Enables username field on the registration form, and allows users to log + * in using their username OR email address. Default is false. + * Accepted values: boolean true or false + */ + 'enable_username' => false, + /** + * Enable Display Name + * Enables a display name field on the registration form, which is persisted + * in the database. Default value is false. + * Accepted values: boolean true or false + */ + 'enable_display_name' => true, + /** + * Authentication Adapters + * Specify the adapters that will be used to try and authenticate the user + * Default value: array containing 'ZfcUser\Authentication\Adapter\Db' with priority 100 + * Accepted values: array containing services that implement 'ZfcUser\Authentication\Adapter\ChainableAdapter' + */ + 'auth_adapters' => [ + 300 => 'UnicaenAuth\Authentication\Adapter\Ldap', // notifié en 1er + 200 => 'UnicaenAuth\Authentication\Adapter\Db', // ensuite (si échec d'authentification Ldap) + 100 => 'UnicaenAuth\Authentication\Adapter\Cas', // ensuite (si échec d'authentification Db) + ], + + // telling ZfcUser to use our own class + 'user_entity_class' => 'UnicaenAuth\Entity\Db\User', + // telling ZfcUserDoctrineORM to skip the entities it defines + 'enable_default_entities' => false, ], + '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. + * + * for ZfcUser, this will be your default identity provider + */ + 'identity_provider' => 'UnicaenAuth\Provider\Identity\Chain', - // 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', + /* role providers simply provide a list of roles that should be inserted + * into the Zend\Acl instance. the module comes with two providers, one + * to specify roles in a config file and one to load roles using a + * Zend\Db adapter. + */ + 'role_providers' => [ + /** + * 2 rôles doivent systématiquement exister dans les ACL : + * - le rôle par défaut 'guest', c'est le rôle de tout utilisateur non authentifié. + * - le rôle 'user', c'est le rôle de tout utilisateur authentifié. + */ + 'UnicaenAuth\Provider\Role\Config' => [ + 'guest' => ['name' => "Non authentifié(e)", 'selectable' => false, 'children' => [ + 'user' => ['name' => "Authentifié(e)", 'selectable' => false], + ]], + ], + /** + * Fournit les rôles issus de la base de données éventuelle de l'appli. + * 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' => [], + /** + * 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 + * sur des ressources. + */ + 'UnicaenAuth\Provider\Role\Username' => [], + ], - /* Currently, only controller and route guards exist - */ - 'guards' => [ - /* If this guard is specified here (i.e. it is enabled), it will block - * access to all controllers and actions unless they are specified here. - * You may omit the 'action' index to allow access to the entire controller + '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', + + /* Currently, only controller and route guards exist */ - 'BjyAuthorize\Guard\Controller' => [ - ['controller' => 'index', 'action' => 'index', 'roles' => []], - ['controller' => 'zfcuser', 'roles' => []], - ['controller' => 'Application\Controller\Index', 'roles' => []], + 'guards' => [ + /* If this guard is specified here (i.e. it is enabled), it will block + * access to all controllers and actions unless they are specified here. + * You may omit the 'action' index to allow access to the entire controller + */ + 'BjyAuthorize\Guard\Controller' => [ + ['controller' => 'index', 'action' => 'index', 'roles' => []], + ['controller' => 'zfcuser', 'roles' => []], + ['controller' => 'Application\Controller\Index', 'roles' => []], - ['controller' => 'UnicaenApp\Controller\Application', 'action' => 'etab', 'roles' => []], - ['controller' => 'UnicaenApp\Controller\Application', 'action' => 'apropos', 'roles' => []], - ['controller' => 'UnicaenApp\Controller\Application', 'action' => 'contact', 'roles' => []], - ['controller' => 'UnicaenApp\Controller\Application', 'action' => 'plan', 'roles' => []], - ['controller' => 'UnicaenApp\Controller\Application', 'action' => 'mentions-legales', 'roles' => []], - ['controller' => 'UnicaenApp\Controller\Application', 'action' => 'informatique-et-libertes', 'roles' => []], - ['controller' => 'UnicaenApp\Controller\Application', 'action' => 'refresh-session', 'roles' => []], - ['controller' => 'UnicaenAuth\Controller\Utilisateur', 'action' => 'selectionner-profil', 'roles' => []], + ['controller' => 'UnicaenApp\Controller\Application', 'action' => 'etab', 'roles' => []], + ['controller' => 'UnicaenApp\Controller\Application', 'action' => 'apropos', 'roles' => []], + ['controller' => 'UnicaenApp\Controller\Application', 'action' => 'contact', 'roles' => []], + ['controller' => 'UnicaenApp\Controller\Application', 'action' => 'plan', 'roles' => []], + ['controller' => 'UnicaenApp\Controller\Application', 'action' => 'mentions-legales', 'roles' => []], + ['controller' => 'UnicaenApp\Controller\Application', 'action' => 'informatique-et-libertes', 'roles' => []], + ['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,8 +393,59 @@ 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' => [ + 'view_helpers' => [ 'factories' => [ 'userConnection' => 'UnicaenAuth\View\Helper\UserConnectionFactory', 'userCurrent' => 'UnicaenAuth\View\Helper\UserCurrentFactory', diff --git a/config/unicaen-auth.global.php.dist b/config/unicaen-auth.global.php.dist index 4fe47f348323938983ab0b2431b40e4b090a1a7f..6be067c42a6d9e83e3c1357753ecc98b47b398a2 100644 --- a/config/unicaen-auth.global.php.dist +++ b/config/unicaen-auth.global.php.dist @@ -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', ]; /** diff --git a/data/schema_mysql.sql b/data/schema_mysql.sql index 35854ecae8e7c815f657050830be98fc52a9c56c..7d22ce0e15a9f7b24352ed65f230a561ce4826fc 100644 --- a/data/schema_mysql.sql +++ b/data/schema_mysql.sql @@ -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 diff --git a/data/schema_oracle.sql b/data/schema_oracle.sql index 6fd8a31623d7940ea65080e09d491cad0280276e..e460e0a3619f4ac5618054a594d602e6e4b700f1 100644 --- a/data/schema_oracle.sql +++ b/data/schema_oracle.sql @@ -1,4 +1,4 @@ -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 diff --git a/src/UnicaenAuth/Assertion/AbstractAssertion.php b/src/UnicaenAuth/Assertion/AbstractAssertion.php new file mode 100644 index 0000000000000000000000000000000000000000..0a589b3fba6fa72de87796dca438c4c33e7340e3 --- /dev/null +++ b/src/UnicaenAuth/Assertion/AbstractAssertion.php @@ -0,0 +1,200 @@ +<?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 diff --git a/src/UnicaenAuth/Controller/DroitsController.php b/src/UnicaenAuth/Controller/DroitsController.php new file mode 100644 index 0000000000000000000000000000000000000000..cb0343fce9b4854f0a9096ae1dea4cda1dd725ff --- /dev/null +++ b/src/UnicaenAuth/Controller/DroitsController.php @@ -0,0 +1,173 @@ +<?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', + 'type' => 'Hidden', + ]); + $form->add([ + 'name' => 'submit', + 'type' => 'Submit', + 'attributes' => [ + 'value' => 'Je confirme la suppression', + ], + ]); + $form->setAttribute('action', $this->url()->fromRoute(null, [], [], true)); + return $form; + } +} \ No newline at end of file diff --git a/src/UnicaenAuth/Entity/Db/CategoriePrivilege.php b/src/UnicaenAuth/Entity/Db/CategoriePrivilege.php new file mode 100644 index 0000000000000000000000000000000000000000..4bc7a34d3cbbbd7f2f0bcc2f7786d42e88a95765 --- /dev/null +++ b/src/UnicaenAuth/Entity/Db/CategoriePrivilege.php @@ -0,0 +1,199 @@ +<?php + +namespace UnicaenAuth\Entity\Db; + +use Doctrine\ORM\Mapping as ORM; + +/** + * + * @ORM\Entity + * @ORM\Table(name="categorie_privilege") + */ +class CategoriePrivilege +{ + /** + * @var int + * @ORM\Id + * @ORM\Column(type="integer") + * @ORM\GeneratedValue(strategy="AUTO") + */ + private $id; + + /** + * @var string + * @ORM\Column(name="code", type="string", length=150, unique=false, nullable=false) + */ + private $code; + + /** + * @var string + * @ORM\Column(name="libelle", type="string", length=200, unique=false, nullable=false) + */ + private $libelle; + + /** + * @var int + * @ORM\Column(name="ordre", type="integer", unique=false, nullable=false) + */ + private $ordre; + + /** + * @var \Doctrine\Common\Collections\Collection + * @ORM\OneToMany(targetEntity="Privilege", mappedBy="categorie") + */ + private $privilege; + + + + /** + * Constructor + */ + public function __construct() + { + $this->privilege = new \Doctrine\Common\Collections\ArrayCollection(); + } + + + + /** + * Set code + * + * @param string $code + * + * @return Privilege + */ + public function setCode($code) + { + $this->code = $code; + + return $this; + } + + + + /** + * Get code + * + * @return string + */ + public function getCode() + { + return $this->code; + } + + + + /** + * Set libelle + * + * @param string $libelle + * + * @return Privilege + */ + public function setLibelle($libelle) + { + $this->libelle = $libelle; + + return $this; + } + + + + /** + * Get libelle + * + * @return string + */ + public function getLibelle() + { + return $this->libelle; + } + + + + /** + * + * @return integer + */ + function getOrdre() + { + return $this->ordre; + } + + + + /** + * + * @param integer $ordre + * + * @return \Application\Entity\Db\Privilege + */ + function setOrdre($ordre) + { + $this->ordre = $ordre; + + return $this; + } + + + + /** + * Get id + * + * @return integer + */ + public function getId() + { + return $this->id; + } + + + + /** + * Add privilege + * + * @param Privilege $privilege + * + * @return Privilege + */ + public function addPrivilege(Privilege $privilege) + { + $this->privilege[] = $privilege; + + return $this; + } + + + + /** + * Remove privilege + * + * @param Privilege $privilege + */ + public function removePrivilege(Privilege $privilege) + { + $this->privilege->removeElement($privilege); + } + + + + /** + * Get privilege + * + * @return \Doctrine\Common\Collections\Collection + */ + public function getPrivilege() + { + return $this->privilege; + } + + + + /** + * @return string + */ + public function __toString() + { + return $this->getLibelle(); + } +} diff --git a/src/UnicaenAuth/Entity/Db/AbstractPrivilege.php b/src/UnicaenAuth/Entity/Db/Privilege.php similarity index 62% rename from src/UnicaenAuth/Entity/Db/AbstractPrivilege.php rename to src/UnicaenAuth/Entity/Db/Privilege.php index 54fab6bba88a2744cd63cb5f469edfaa6806fb68..45f4dcddb708aaa439a6541edbea2d903659f47d 100644 --- a/src/UnicaenAuth/Entity/Db/AbstractPrivilege.php +++ b/src/UnicaenAuth/Entity/Db/Privilege.php @@ -1,41 +1,59 @@ <?php namespace UnicaenAuth\Entity\Db; + +use UnicaenAuth\Provider\Privilege\Privileges; use Zend\Permissions\Acl\Resource\ResourceInterface; +use Doctrine\ORM\Mapping as ORM; /** - * Privilege + * + * @ORM\Entity + * @ORM\Table(name="privilege") */ -abstract class AbstractPrivilege implements ResourceInterface +class Privilege implements ResourceInterface { + /** + * @var int + * @ORM\Id + * @ORM\Column(type="integer") + * @ORM\GeneratedValue(strategy="AUTO") + */ + private $id; + /** * @var string + * @ORM\Column(name="code", type="string", length=150, unique=false, nullable=false) */ private $code; /** * @var string + * @ORM\Column(name="libelle", type="string", length=200, unique=false, nullable=false) */ private $libelle; /** - * - * @var integer + * @var int + * @ORM\Column(name="ordre", type="integer", unique=false, nullable=false) */ private $ordre; /** - * @var integer - */ - private $id; - - /** - * @var \UnicaenApp\Entity\Db\CategoriePrivilege + * @var CategoriePrivilege + * @ORM\ManyToOne(targetEntity="CategoriePrivilege", inversedBy="privilege") + * @ORM\JoinColumn(name="categorie_id", referencedColumnName="id") */ private $categorie; /** - * @var \Doctrine\Common\Collections\Collection + * @ORM\ManyToMany(targetEntity="UnicaenAuth\Entity\Db\Role",cascade={"all"}) + * @ORM\JoinTable( + * name="role_privilege", + * joinColumns={@ORM\JoinColumn(name="privilege_id", referencedColumnName="id", onDelete="cascade")}, + * inverseJoinColumns={@ORM\JoinColumn(name="role_id", referencedColumnName="id", onDelete="cascade")} + * + * ) */ private $role; @@ -129,7 +147,7 @@ abstract class AbstractPrivilege implements ResourceInterface * * @param integer $ordre * - * @return \Application\Entity\Db\Privilege + * @return self */ function setOrdre($ordre) { @@ -155,11 +173,11 @@ abstract class AbstractPrivilege implements ResourceInterface /** * Set categorie * - * @param \Application\Entity\Db\CategoriePrivilege $categorie + * @param CategoriePrivilege $categorie * - * @return Privilege + * @return self */ - public function setCategorie(\Application\Entity\Db\CategoriePrivilege $categorie = null) + public function setCategorie(CategoriePrivilege $categorie = null) { $this->categorie = $categorie; @@ -171,7 +189,7 @@ abstract class AbstractPrivilege implements ResourceInterface /** * Get categorie * - * @return \Application\Entity\Db\CategoriePrivilege + * @return CategoriePrivilege */ public function getCategorie() { @@ -183,13 +201,13 @@ abstract class AbstractPrivilege implements ResourceInterface /** * Add role * - * @param \Application\Entity\Db\Role $role + * @param Role $role * - * @return Privilege + * @return self */ - public function addRole(\Application\Entity\Db\Role $role) + public function addRole(Role $role) { - $this->Role[] = $role; + $this->role->add($role); return $this; } @@ -199,9 +217,9 @@ abstract class AbstractPrivilege implements ResourceInterface /** * Remove role * - * @param \Application\Entity\Db\Role $role + * @param Role $role */ - public function removeRole(\Application\Entity\Db\Role $role) + public function removeRole(Role $role) { $this->role->removeElement($role); } @@ -220,23 +238,6 @@ abstract class AbstractPrivilege implements ResourceInterface - /** - * @deprecated - * @todo à voir si cela sert à quelque chose ou non !! - * @return array - */ - public function getRoleCodes() - { - $result = []; - foreach ($this->role as $role) { - /* @var $role Role */ - $result[] = $role->getRoleId(); - } - return $result; - } - - - /** * @return string */ @@ -252,6 +253,6 @@ abstract class AbstractPrivilege implements ResourceInterface */ public function getResourceId() { - return sprintf('privilege/%s', $this->getFullCode()); + return Privileges::getResource($this); } } diff --git a/src/UnicaenAuth/Entity/Db/Role.php b/src/UnicaenAuth/Entity/Db/Role.php index 472740fac9e9abf6299621ed31f0a5745b5880fe..dc358a5eafe2339c42d11871d558fa6af29d7fdc 100644 --- a/src/UnicaenAuth/Entity/Db/Role.php +++ b/src/UnicaenAuth/Entity/Db/Role.php @@ -35,9 +35,9 @@ class Role implements HierarchicalRoleInterface /** * @var boolean - * @ORM\Column(name="is_default", type="boolean", nullable=false) + * @ORM\Column(name="is_default", type="boolean", nullable=true) */ - protected $isDefault; + protected $isDefault = false; /** * @var Role diff --git a/src/UnicaenAuth/Form/Droits/RoleForm.php b/src/UnicaenAuth/Form/Droits/RoleForm.php new file mode 100644 index 0000000000000000000000000000000000000000..e2f5de973ff2e281eb28ee99140aff4921a16d6f --- /dev/null +++ b/src/UnicaenAuth/Form/Droits/RoleForm.php @@ -0,0 +1,141 @@ +<?php + +namespace UnicaenAuth\Form\Droits; + +use UnicaenAuth\Entity\Db\Role; +use UnicaenAuth\Service\Traits\RoleServiceAwareTrait; +use Zend\Form\Form; +use UnicaenApp\Util; +use Zend\ServiceManager\ServiceLocatorAwareInterface; +use Zend\ServiceManager\ServiceLocatorAwareTrait; +use Zend\Stdlib\Hydrator\HydratorInterface; + +/** + * Description of RoleForm + * + * @author Laurent LECLUSE <laurent.lecluse at unicaen.fr> + */ +class RoleForm extends Form implements ServiceLocatorAwareInterface +{ + use ServiceLocatorAwareTrait; + use RoleServiceAwareTrait; + + public function init() + { + $hydrator = new RoleFormHydrator; + $hydrator->setServiceRole( $this->getServiceRole() ); + $this->setHydrator($hydrator); + + $this->add([ + 'type' => 'Text', + 'name' => 'role-id', + 'options' => [ + 'label' => 'Nom', + ], + ]); + + $this->add([ + 'type' => 'Text', + 'name' => 'ldap-filter', + 'options' => [ + 'label' => 'Filtre LDAP', + ], + ]); + + $this->add([ + 'type' => 'Select', + 'name' => 'parent', + 'options' => [ + 'label' => 'Parent', + 'empty_option' => '- Aucun -', + 'value_options' => Util::collectionAsOptions($this->getServiceRole()->getList()), + ], + ]); + + $this->add([ + 'name' => 'id', + 'type' => 'Hidden', + ]); + + $this->add([ + 'name' => 'submit', + 'type' => 'Submit', + 'attributes' => [ + 'value' => 'Enregistrer', + 'class' => 'btn btn-primary', + ], + ]); + } + + + + /** + * Should return an array specification compatible with + * {@link Zend\InputFilter\Factory::createInputFilter()}. + * + * @return array + */ + public function getInputFilterSpecification() + { + return [ + 'role-id' => [ + 'required' => true, + ], + 'ldap-filter' => [ + 'required' => false, + ], + 'parent' => [ + 'required' => false, + ], + ]; + } +} + + + + + +/** + * Class RoleFormHydrator + * + * @package UnicaenAuth\Form\Droits + * @author Laurent LÉCLUSE <laurent.lecluse at unicaen.fr> + */ +class RoleFormHydrator implements HydratorInterface +{ + use RoleServiceAwareTrait; + + /** + * @param array $data + * @param Role $object + * + * @return object + */ + public function hydrate(array $data, $object) + { + $object->setRoleId($data['role-id']); + $object->setLdapFilter($data['ldap-filter'] ?: null); + $object->setParent($this->getServiceRole()->get($data['parent'])); + + return $object; + } + + + + /** + * @param Role $object + * + * @return array + */ + public function extract($object) + { + $data = [ + 'id' => $object->getId(), + 'role-id' => $object->getRoleId(), + 'ldap-filter' => $object->getLdapFilter(), + 'parent' => $object->getParent() ? $object->getParent()->getId() : null, + ]; + + return $data; + } +} \ No newline at end of file diff --git a/src/UnicaenAuth/Form/Droits/Traits/RoleFormAwareTrait.php b/src/UnicaenAuth/Form/Droits/Traits/RoleFormAwareTrait.php new file mode 100755 index 0000000000000000000000000000000000000000..02badad1729fccad2d0496df10986806196fd704 --- /dev/null +++ b/src/UnicaenAuth/Form/Droits/Traits/RoleFormAwareTrait.php @@ -0,0 +1,58 @@ +<?php + +namespace UnicaenAuth\Form\Droits\Traits; + +use UnicaenAuth\Form\Droits\RoleForm; +use RuntimeException; + +/** + * Description of RoleFormAwareTrait + * + * @author UnicaenCode + */ +trait RoleFormAwareTrait +{ + /** + * @var RoleForm + */ + private $formDroitsRole; + + + + /** + * @param RoleForm $formDroitsRole + * + * @return self + */ + public function setFormDroitsRole(RoleForm $formDroitsRole) + { + $this->formDroitsRole = $formDroitsRole; + + return $this; + } + + + + /** + * @return RoleForm + * @throws RuntimeException + */ + public function getFormDroitsRole() + { + if (empty($this->formDroitsRole)) { + + if (!method_exists($this, 'getServiceLocator')) { + throw new RuntimeException('La classe ' . get_class($this) . ' n\'a pas accès au ServiceLocator.'); + } + + $serviceLocator = $this->getServiceLocator(); + if (method_exists($serviceLocator, 'getServiceLocator')) { + $serviceLocator = $serviceLocator->getServiceLocator(); + } + + $this->formDroitsRole = $serviceLocator->get('FormElementManager')->get('UnicaenAuth\Form\Droits\Role'); + } + + return $this->formDroitsRole; + } +} \ No newline at end of file diff --git a/src/UnicaenAuth/Guard/PrivilegeController.php b/src/UnicaenAuth/Guard/PrivilegeController.php new file mode 100644 index 0000000000000000000000000000000000000000..99b4f2d5158d71343f774be4730b6faba5500331 --- /dev/null +++ b/src/UnicaenAuth/Guard/PrivilegeController.php @@ -0,0 +1,87 @@ +<?php + +namespace UnicaenAuth\Guard; + +use BjyAuthorize\Guard\Controller; +use Zend\ServiceManager\ServiceLocatorInterface; +use UnicaenAuth\Provider\Privilege\PrivilegeProviderAwareTrait; +use UnicaenApp\Traits\SessionContainerTrait; + + +/** + * Description of ControllerGuard + * + * @author Laurent LECLUSE <laurent.lecluse at unicaen.fr> + */ +class PrivilegeController extends Controller +{ + use PrivilegeProviderAwareTrait; + use SessionContainerTrait; + + + + public function __construct(array $rules, ServiceLocatorInterface $serviceLocator) + { + $this->serviceLocator = $serviceLocator; + parent::__construct($this->privilegesToRoles($rules), $serviceLocator); + } + + + + protected function privilegesToRoles(array $rules) + { +// $session = $this->getSessionContainer(); +// if (! isset($session->rules)){ + + $pr = $this->getPrivilegeProvider()->getPrivilegesRoles(); + + foreach ($rules as $index => $rule) { + if (isset($rule['privileges'])) { + $rolesCount = 0; + $privileges = (array)$rule['privileges']; + $rule['roles'] = isset($rule['roles']) ? (array)$rule['roles'] : []; + foreach ($pr as $privilege => $roles) { + if (in_array($privilege, $privileges)) { + $rolesCount += count($roles); + $rule['roles'] = array_unique(array_merge($rule['roles'], $roles)); + } + } + unset($rule['privileges']); + if (0 < count($rule['roles'])) { + $rules[$index] = $rule; + }else{ + unset($rules[$index]); + } + } + } + + return $rules; +// $session->rules = $rules; +// } +// return $session->rules; + } + + + + /** + * Pour récupérer le serviceLocator depuis les traits de service + * + * @return ServiceLocatorInterface + */ + protected function getServiceLocator() + { + return $this->serviceLocator; + } + + + + public static function getResourceId($controller, $action = null) + { + if (isset($action)) { + return sprintf('controller/%s:%s', $controller, strtolower($action)); + } + + return sprintf('controller/%s', $controller); + } + +} \ No newline at end of file diff --git a/src/UnicaenAuth/Options/ModuleOptions.php b/src/UnicaenAuth/Options/ModuleOptions.php index 4f806e5249852123707e321c723e9564fd493ece..c5f942aa1972f0a539647a42adcfdda7fac5d7d3 100644 --- a/src/UnicaenAuth/Options/ModuleOptions.php +++ b/src/UnicaenAuth/Options/ModuleOptions.php @@ -23,18 +23,29 @@ class ModuleOptions extends \ZfcUser\Options\ModuleOptions */ protected $cas = []; + /** + * @var string + */ + protected $entityManagerName = 'doctrine.entitymanager.orm_default'; + + + /** * set usernames allowed to make usurpation * * @param array $usurpationAllowedUsernames + * * @return ModuleOptions */ public function setUsurpationAllowedUsernames(array $usurpationAllowedUsernames = []) { $this->usurpationAllowedUsernames = $usurpationAllowedUsernames; + return $this; } + + /** * get usernames allowed to make usurpation * @@ -45,19 +56,25 @@ class ModuleOptions extends \ZfcUser\Options\ModuleOptions return $this->usurpationAllowedUsernames; } + + /** * Spécifie si l'utilisateur authentifié doit être enregistré dans la base * de données de l'appli * * @param bool $flag + * * @return ModuleOptions */ public function setSaveLdapUserInDatabase($flag = true) { - $this->saveLdapUserInDatabase = (bool) $flag; + $this->saveLdapUserInDatabase = (bool)$flag; + return $this; } + + /** * Retourne la valeur du flag spécifiant si l'utilisateur authentifié doit être * enregistré dans la base de données de l'appli @@ -69,18 +86,24 @@ class ModuleOptions extends \ZfcUser\Options\ModuleOptions return $this->saveLdapUserInDatabase; } + + /** * set cas connection params * * @param array $cas + * * @return ModuleOptions */ public function setCas(array $cas = []) { $this->cas = $cas; + return $this; } + + /** * get cas connection params * @@ -90,4 +113,30 @@ class ModuleOptions extends \ZfcUser\Options\ModuleOptions { return $this->cas; } + + + + /** + * @return string + */ + public function getEntityManagerName() + { + return $this->entityManagerName; + } + + + + /** + * @param string $entityManagerName + * + * @return ModuleOptions + */ + public function setEntityManagerName($entityManagerName) + { + $this->entityManagerName = $entityManagerName; + + return $this; + } + + } \ No newline at end of file diff --git a/src/UnicaenAuth/Options/Traits/ModuleOptionsAwareTrait.php b/src/UnicaenAuth/Options/Traits/ModuleOptionsAwareTrait.php new file mode 100644 index 0000000000000000000000000000000000000000..7d54cc5877fb515005194fd08ea2018da344e446 --- /dev/null +++ b/src/UnicaenAuth/Options/Traits/ModuleOptionsAwareTrait.php @@ -0,0 +1,56 @@ +<?php + +namespace UnicaenAuth\Options\Traits; + +use UnicaenAuth\Options\ModuleOptions; +use RuntimeException; + +/** + * Description of ModuleOptionsAwareTrait + * + * @author Laurent LÉCLUSE <laurent.lecluse at unicaen.fr> + */ +trait ModuleOptionsAwareTrait +{ + /** + * @var ModuleOptions + */ + private $moduleOptions; + + + + /** + * @param ModuleOptions $moduleOptions + * + * @return self + */ + public function setModuleOptions(ModuleOptions $moduleOptions) + { + $this->moduleOptions = $moduleOptions; + + return $this; + } + + + + /** + * @return ModuleOptions + * @throws RuntimeException + */ + public function getModuleOptions() + { + if (empty($this->moduleOptions)) { + if (!method_exists($this, 'getServiceLocator')) { + throw new RuntimeException('La classe ' . get_class($this) . ' n\'a pas accès au ServiceLocator.'); + } + + $serviceLocator = $this->getServiceLocator(); + if (method_exists($serviceLocator, 'getServiceLocator')) { + $serviceLocator = $serviceLocator->getServiceLocator(); + } + $this->moduleOptions = $serviceLocator->get('unicaen-auth_module_options'); + } + + return $this->moduleOptions; + } +} \ No newline at end of file diff --git a/src/UnicaenAuth/Provider/Identity/Chain.php b/src/UnicaenAuth/Provider/Identity/Chain.php index 59308d5bcee0a80bae5b5c1000e65f05d656de4c..67c2c61565ebe0a8597027c707b3ef09264a94f8 100644 --- a/src/UnicaenAuth/Provider/Identity/Chain.php +++ b/src/UnicaenAuth/Provider/Identity/Chain.php @@ -41,8 +41,8 @@ class Chain implements ProviderInterface, ServiceLocatorAwareInterface, EventMan */ public function getIdentityRoles() { - $selectedIdentityRole = $this->getSelectedIdentityRole(); $allRoles = $this->getAllIdentityRoles(); + $selectedIdentityRole = $this->getSelectedIdentityRole(); $roles = $selectedIdentityRole ? [$selectedIdentityRole] : $allRoles; return $roles; diff --git a/src/UnicaenAuth/Provider/Identity/Db.php b/src/UnicaenAuth/Provider/Identity/Db.php index f0d7ebb5e337304495f8c12fcc2c9ca3ae2e66e8..baa3f1453eb21b3538bc4169011a0e09bf91de18 100644 --- a/src/UnicaenAuth/Provider/Identity/Db.php +++ b/src/UnicaenAuth/Provider/Identity/Db.php @@ -3,6 +3,11 @@ namespace UnicaenAuth\Provider\Identity; use BjyAuthorize\Provider\Identity\AuthenticationIdentityProvider; use BjyAuthorize\Provider\Role\ProviderInterface; +use UnicaenApp\Entity\Ldap\People; +use UnicaenAuth\Entity\Db\Role; +use UnicaenAuth\Service\Traits\RoleServiceAwareTrait; +use Zend\Ldap\Ldap; +use Zend\ServiceManager\ServiceLocatorAwareTrait; use ZfcUser\Entity\UserInterface; use Traversable; @@ -16,8 +21,17 @@ use Traversable; * * @author Bertrand GAUTHIER <bertrand.gauthier at unicaen.fr> */ -class Db extends AuthenticationIdentityProvider implements ChainableProvider +class Db extends AuthenticationIdentityProvider implements ChainableProvider, \BjyAuthorize\Provider\Identity\ProviderInterface { + use RoleServiceAwareTrait; + + /** + * @var Ldap + */ + private $ldap; + + + /** * {@inheritDoc} */ @@ -26,17 +40,26 @@ class Db extends AuthenticationIdentityProvider implements ChainableProvider $event->addRoles($this->getIdentityRoles()); } + + /** * {@inheritDoc} */ public function getIdentityRoles() { - if (!($identity = $this->authService->getIdentity())) { + if (!($idArray = $this->authService->getIdentity())) { return [$this->defaultRole]; } - if (is_array($identity) && isset($identity['db'])) { - $identity = $identity['db']; + $ldapDn = null; + $identity = null; + if (is_array($idArray)) { + if (isset($idArray['ldap']) && $idArray['ldap'] instanceof People) { + $ldapDn = $idArray['ldap']->getDn(); + } + if (isset($idArray['db'])) { + $identity = $idArray['db']; + } } if ($identity instanceof ProviderInterface) { @@ -44,8 +67,7 @@ class Db extends AuthenticationIdentityProvider implements ChainableProvider if ($roles instanceof Traversable) { $roles = iterator_to_array($roles); } - } - else { + } else { $roles = []; } @@ -53,6 +75,61 @@ class Db extends AuthenticationIdentityProvider implements ChainableProvider $roles[] = $identity->getUsername(); } + /* Injection des rôles par filtre LDAP */ + $ldapRoles = $this->getServiceRole()->getList(); + foreach ($ldapRoles as $role) { + if ($role->getLdapFilter() && !in_array($role, $roles)) { + if ($this->roleMatches($role, $ldapDn)) { + $roles[] = $role; + } + } + } + return $roles; } + + + + /** + * @param Role $role + * @param string $dn + * + * @return bool + */ + protected function roleMatches(Role $role, $dn) + { + try { + return 1 === $this->getLdap()->count($role->getLdapFilter(), $dn, Ldap::SEARCH_SCOPE_SUB); + } catch (\Zend\Ldap\Exception\LdapException $e) { + return false; + } + } + + + + /** + * Returns the LDAP Object + * + * @return Ldap + */ + public function getLdap() + { + return $this->ldap; + } + + + + /** + * Set an Ldap connection + * + * @param Ldap $ldap + * + * @return self + */ + public function setLdap(Ldap $ldap) + { + $this->ldap = $ldap; + + return $this; + } } \ No newline at end of file diff --git a/src/UnicaenAuth/Provider/Identity/DbServiceFactory.php b/src/UnicaenAuth/Provider/Identity/DbServiceFactory.php index afd4eb349c62402a65569d15e400a1cceabb20bb..a326639d8d78e3ce161381f813744f627d87760a 100644 --- a/src/UnicaenAuth/Provider/Identity/DbServiceFactory.php +++ b/src/UnicaenAuth/Provider/Identity/DbServiceFactory.php @@ -2,6 +2,8 @@ namespace UnicaenAuth\Provider\Identity; +use UnicaenApp\Options\ModuleOptions; +use Zend\Ldap\Ldap; use Zend\ServiceManager\FactoryInterface; use Zend\ServiceManager\ServiceLocatorInterface; @@ -17,10 +19,18 @@ class DbServiceFactory implements FactoryInterface */ public function createService(ServiceLocatorInterface $serviceLocator) { - $user = $serviceLocator->get('zfcuser_user_service'); - $config = $serviceLocator->get('BjyAuthorize\Config'); - $identityProvider = new Db($user->getAuthService()); + $user = $serviceLocator->get('zfcuser_user_service'); + $identityProvider = new Db($user->getAuthService()); + + $unicaenAppOptions = $serviceLocator->get('unicaen-app_module_options'); + /* @var $unicaenAppOptions ModuleOptions */ + + $ldap = new Ldap($unicaenAppOptions->getLdap()['connection']['default']['params']); + $identityProvider->setLdap($ldap); + $identityProvider->setServiceRole($serviceLocator->get('UnicaenAuth\Service\Role')); + + $config = $serviceLocator->get('BjyAuthorize\Config'); $identityProvider->setDefaultRole($config['default_role']); $identityProvider->setAuthenticatedRole($config['authenticated_role']); diff --git a/src/UnicaenAuth/Provider/Identity/Ldap.php b/src/UnicaenAuth/Provider/Identity/Ldap.php index b210db212fb159eb16c6ed5f58089dabbfbeb855..c107a59ed00f7615e50924b36bcd3ef89a0effa6 100644 --- a/src/UnicaenAuth/Provider/Identity/Ldap.php +++ b/src/UnicaenAuth/Provider/Identity/Ldap.php @@ -14,6 +14,7 @@ use ZfcUser\Entity\UserInterface; * - L'identité authentifiée est fournie par le service d'authentification. * * @author Bertrand GAUTHIER <bertrand.gauthier at unicaen.fr> + * @deprecated */ class Ldap extends AuthenticationIdentityProvider implements ChainableProvider { diff --git a/src/UnicaenAuth/Provider/Identity/LdapServiceFactory.php b/src/UnicaenAuth/Provider/Identity/LdapServiceFactory.php index f4b283f82a5ec3ed79983048fe2a083e149578f4..3209e8690bab08d3c8e1f37de37e049297b749dc 100644 --- a/src/UnicaenAuth/Provider/Identity/LdapServiceFactory.php +++ b/src/UnicaenAuth/Provider/Identity/LdapServiceFactory.php @@ -15,6 +15,7 @@ class LdapServiceFactory implements FactoryInterface { /** * {@inheritDoc} + * @deprecated */ public function createService(ServiceLocatorInterface $serviceLocator) { diff --git a/src/UnicaenAuth/Provider/Privilege/PrivilegeProviderAwareTrait.php b/src/UnicaenAuth/Provider/Privilege/PrivilegeProviderAwareTrait.php new file mode 100644 index 0000000000000000000000000000000000000000..ba6abd90ad0fb5d5c82f4f74c56eb52b1f3debb0 --- /dev/null +++ b/src/UnicaenAuth/Provider/Privilege/PrivilegeProviderAwareTrait.php @@ -0,0 +1,48 @@ +<?php + +namespace UnicaenAuth\Provider\Privilege; + +trait PrivilegeProviderAwareTrait +{ + /** + * description + * + * @var PrivilegeProviderInterface + */ + private $privilegeProvider; + + /** + * + * @param PrivilegeProviderInterface $privilegeProvider + * @return self + */ + public function setPrivilegeProvider( PrivilegeProviderInterface $privilegeProvider ) + { + $this->privilegeProvider = $privilegeProvider; + return $this; + } + + /** + * + * @return PrivilegeProviderInterface + * @throws \Common\Exception\RuntimeException + */ + public function getPrivilegeProvider() + { + if (empty($this->privilegeProvider)){ + if (! method_exists($this, 'getServiceLocator')) { + throw new \Exception( 'La classe '.get_class($this).' n\'a pas accès au ServiceLocator.'); + } + + $serviceLocator = $this->getServiceLocator(); + if (method_exists($serviceLocator, 'getServiceLocator')) { + $serviceLocator = $serviceLocator->getServiceLocator(); + } + + return $serviceLocator->get('UnicaenAuth\Privilege\PrivilegeProvider'); + }else{ + return $this->privilegeProvider; + } + } + +} \ No newline at end of file diff --git a/src/UnicaenAuth/Provider/Privilege/PrivilegeProviderInterface.php b/src/UnicaenAuth/Provider/Privilege/PrivilegeProviderInterface.php new file mode 100644 index 0000000000000000000000000000000000000000..b5ad26694ce2a7c75394a9a1f1b918b3d3f75e1a --- /dev/null +++ b/src/UnicaenAuth/Provider/Privilege/PrivilegeProviderInterface.php @@ -0,0 +1,21 @@ +<?php + +namespace UnicaenAuth\Provider\Privilege; + +interface PrivilegeProviderInterface +{ + + /** + * Retourne un tableau à deux dimentions composé de chaînes de caractère UNIQUEMENT + * + * Format du tableau : + * [ + * 'privilege_a' => ['role_1', ...], + * 'privilege_b' => ['role_1', 'role_2', ...], + * ] + * + * @return string[][] + */ + public function getPrivilegesRoles(); + +} \ No newline at end of file diff --git a/src/UnicaenAuth/Provider/Privilege/Privileges.php b/src/UnicaenAuth/Provider/Privilege/Privileges.php new file mode 100644 index 0000000000000000000000000000000000000000..5263eaee915582b258e6526f94a7dc26d982982c --- /dev/null +++ b/src/UnicaenAuth/Provider/Privilege/Privileges.php @@ -0,0 +1,31 @@ +<?php + +namespace UnicaenAuth\Provider\Privilege; + +use UnicaenAuth\Entity\Db\Privilege; + +class Privileges { + + const DROIT_ROLE_VISUALISATION = 'droit-role-visualisation'; + const DROIT_ROLE_EDITION = 'droit-role-edition'; + const DROIT_PRIVILEGE_VISUALISATION = 'droit-privilege-visualisation'; + const DROIT_PRIVILEGE_EDITION = 'droit-privilege-edition'; + + + + /** + * Retourne le nom de la ressource associée au privilège donné + * + * @param $privilege + * + * @return string + */ + public static function getResource( $privilege ) + { + if ($privilege instanceof Privilege){ + $privilege = $privilege->getFullCode(); + } + return 'privilege/'.$privilege; + } + +} \ No newline at end of file diff --git a/src/UnicaenAuth/Provider/Role/DbRoleServiceFactory.php b/src/UnicaenAuth/Provider/Role/DbRoleServiceFactory.php index 26fa008536539c3541818e0684334a520d87b13a..ab238ca040b0336fcfdbc68a1784044eb8c86b21 100644 --- a/src/UnicaenAuth/Provider/Role/DbRoleServiceFactory.php +++ b/src/UnicaenAuth/Provider/Role/DbRoleServiceFactory.php @@ -3,6 +3,7 @@ namespace UnicaenAuth\Provider\Role; use BjyAuthorize\Exception\InvalidArgumentException; +use UnicaenAuth\Service\RoleService; use Zend\ServiceManager\FactoryInterface; use Zend\ServiceManager\ServiceLocatorInterface; @@ -18,27 +19,9 @@ class DbRoleServiceFactory implements FactoryInterface */ public function createService(ServiceLocatorInterface $serviceLocator) { - $config = $serviceLocator->get('BjyAuthorize\Config'); + $serviceRole = $serviceLocator->get('UnicaenAuth\Service\Role'); + /* @var $serviceRole RoleService */ - if (! isset($config['role_providers']['UnicaenAuth\Provider\Role\DbRole'])) { - throw new InvalidArgumentException( - 'Config for "UnicaenAuth\Provider\Role\DbRole" not set' - ); - } - - $providerConfig = $config['role_providers']['UnicaenAuth\Provider\Role\DbRole']; - - if (! isset($providerConfig['role_entity_class'])) { - throw new InvalidArgumentException('role_entity_class not set in the bjyauthorize role_providers config.'); - } - - if (! isset($providerConfig['object_manager'])) { - throw new InvalidArgumentException('object_manager not set in the bjyauthorize role_providers config.'); - } - - /* @var $objectManager \Doctrine\Common\Persistence\ObjectManager */ - $objectManager = $serviceLocator->get($providerConfig['object_manager']); - - return new DbRole($objectManager->getRepository($providerConfig['role_entity_class'])); + return new DbRole($serviceRole->getRepo()); } } diff --git a/src/UnicaenAuth/Provider/Rule/PrivilegeRuleProvider.php b/src/UnicaenAuth/Provider/Rule/PrivilegeRuleProvider.php new file mode 100644 index 0000000000000000000000000000000000000000..99fdba217e97411e03d0ddf996b4b793fd9405bb --- /dev/null +++ b/src/UnicaenAuth/Provider/Rule/PrivilegeRuleProvider.php @@ -0,0 +1,87 @@ +<?php + +namespace UnicaenAuth\Provider\Rule; + +use BjyAuthorize\Provider\Rule\ProviderInterface; +use Zend\ServiceManager\ServiceLocatorInterface; +use Zend\ServiceManager\ServiceLocatorAwareTrait; +use UnicaenAuth\Provider\Privilege\PrivilegeProviderAwareTrait; + +/** + * Rule provider based on a given array of rules + * + * @author Laurent LÉCLUSE <laurent.lecluse at unicaen.fr> + */ +class PrivilegeRuleProvider implements ProviderInterface +{ + use ServiceLocatorAwareTrait; + use PrivilegeProviderAwareTrait; + + /** + * @var array + */ + protected $rules; + + + /** + * @param array $config + */ + public function __construct(array $config, ServiceLocatorInterface $serviceLocator) + { + $this->setServiceLocator($serviceLocator); + + $this->rules = $this->makeRules($config); + } + + + + public function makeRules(array $config) + { + $pr = $this->getPrivilegeProvider()->getPrivilegesRoles(); + + foreach ($config as $grant => $rules) { + foreach ($rules as $index => $rule) { + if (is_array($rule)) { + $privileges = (array)$rule['privileges']; + $ressources = $rule['resources']; + $assertion = isset($rule['assertion']) ? $rule['assertion'] : null; + $bjyRoles = []; + foreach ($pr as $privilege => $roles) { + if (in_array($privilege, $privileges)) { + $bjyRoles = array_unique(array_merge($bjyRoles, $roles)); + } + } + + $bjyRule = [ + $bjyRoles, + $ressources, + $privileges, + ]; + if ($assertion) $bjyRule[3] = $assertion; + + $config[$grant][$index] = $bjyRule; + } + } + } + $rules = $config; + if (!isset($rules['allow'])) $rules['allow'] = []; + foreach ($pr as $privilege => $roles) { + $rules['allow'][] = [ + $roles, + 'privilege/' . $privilege, + ]; + } + + return $rules; + } + + + + /** + * {@inheritDoc} + */ + public function getRules() + { + return $this->rules; + } +} diff --git a/src/UnicaenAuth/Service/AbstractService.php b/src/UnicaenAuth/Service/AbstractService.php new file mode 100644 index 0000000000000000000000000000000000000000..0feb2a0e06f53d94fd4576d85f14eb9fdcfef52c --- /dev/null +++ b/src/UnicaenAuth/Service/AbstractService.php @@ -0,0 +1,49 @@ +<?php + +namespace UnicaenAuth\Service; + +use UnicaenApp\Service\EntityManagerAwareTrait; +use UnicaenAuth\Options\ModuleOptions; +use Zend\ServiceManager\ServiceLocatorAwareInterface; +use Zend\ServiceManager\ServiceLocatorAwareTrait; + +abstract class AbstractService implements ServiceLocatorAwareInterface +{ + use ServiceLocatorAwareTrait; + use EntityManagerAwareTrait; + + /** + * @var \BjyAuthorize\Service\Authorize + */ + private $serviceAuthorize; + + + + /** + * @return \BjyAuthorize\Service\Authorize + */ + protected function getServiceAuthorize() + { + if (!$this->serviceAuthorize) { + $this->serviceAuthorize = $this->getServiceLocator()->get('BjyAuthorize\Service\Authorize'); + } + + return $this->serviceAuthorize; + } + + + + /** + * @return \Doctrine\ORM\EntityManager + */ + protected function getEntityManager() + { + if (!$this->entityManager) { + $moduleOptions = $this->getServiceLocator()->get('unicaen-auth_module_options'); + /* @var $moduleOptions ModuleOptions */ + $this->entityManager = $this->getServiceLocator()->get($moduleOptions->getEntityManagerName()); + } + + return $this->entityManager; + } +} diff --git a/src/UnicaenAuth/Service/AuthorizeService.php b/src/UnicaenAuth/Service/AuthorizeService.php new file mode 100644 index 0000000000000000000000000000000000000000..c038340c39c02d46dabe12b4efd22b7ae80dc302 --- /dev/null +++ b/src/UnicaenAuth/Service/AuthorizeService.php @@ -0,0 +1,62 @@ +<?php +/** + * BjyAuthorize Module (https://github.com/bjyoungblood/BjyAuthorize) + * + * @link https://github.com/bjyoungblood/BjyAuthorize for the canonical source repository + * @license http://framework.zend.com/license/new-bsd New BSD License + */ + +namespace UnicaenAuth\Service; +use UnicaenAuth\Service\Traits\UserContextServiceAwareTrait; + +/** + * Authorize service + * + * @author Laurent LÉCLUSE <laurent.lecluse at unicaen.fr> + */ +class AuthorizeService extends \BjyAuthorize\Service\Authorize +{ + use UserContextServiceAwareTrait; + + /** + * Loading... + * + * @var boolean + */ + protected $loading; + + + public function getServiceLocator() + { + return $this->serviceLocator; + } + + /** + * @deprecated this method will be removed in BjyAuthorize 1.4.x+, + * please retrieve the identity from the + * `BjyAuthorize\Provider\Identity\ProviderInterface` service + * + * @return string + */ + public function getIdentity() + { + $this->loaded && $this->loaded->__invoke(); + if ($this->loading) return 'bjyauthorize-identity'; + return $this->getServiceUserContext()->getSelectedIdentityRole(); + } + + /** + * Initializes the service + * + * @internal + * + * @return void + */ + public function load() + { + $this->loading = true; + parent::load(); + $this->loading = false; + } + +} diff --git a/src/UnicaenAuth/Service/AuthorizeServiceFactory.php b/src/UnicaenAuth/Service/AuthorizeServiceFactory.php new file mode 100644 index 0000000000000000000000000000000000000000..14b7857cc93d06890879e84219030a4c489e1c2d --- /dev/null +++ b/src/UnicaenAuth/Service/AuthorizeServiceFactory.php @@ -0,0 +1,30 @@ +<?php +/** + * BjyAuthorize Module (https://github.com/bjyoungblood/BjyAuthorize) + * + * @link https://github.com/bjyoungblood/BjyAuthorize for the canonical source repository + * @license http://framework.zend.com/license/new-bsd New BSD License + */ + +namespace UnicaenAuth\Service; + +use Zend\ServiceManager\FactoryInterface; +use Zend\ServiceManager\ServiceLocatorInterface; + +/** + * Factory responsible of building the {@see \BjyAuthorize\Service\Authorize} service + * + * @author Laurent LÉCLUSE <laurent.lecluse at unicaen.fr> + */ +class AuthorizeServiceFactory implements FactoryInterface +{ + /** + * {@inheritDoc} + * + * @return \Application\Service\Authorize + */ + public function createService(ServiceLocatorInterface $serviceLocator) + { + return new AuthorizeService($serviceLocator->get('BjyAuthorize\Config'), $serviceLocator); + } +} diff --git a/src/UnicaenAuth/Service/CategoriePrivilegeService.php b/src/UnicaenAuth/Service/CategoriePrivilegeService.php new file mode 100644 index 0000000000000000000000000000000000000000..680fa2ec356268e0ddaa01c63133eed483071bbe --- /dev/null +++ b/src/UnicaenAuth/Service/CategoriePrivilegeService.php @@ -0,0 +1,23 @@ +<?php + +namespace UnicaenAuth\Service; + +use UnicaenAuth\Entity\Db\CategoriePrivilege; + + +class CategoriePrivilegeService extends AbstractService +{ + + /** + * @return CategoriePrivilege[] + */ + public function getCategoriesPrivileges() + { + $dql = 'SELECT cp FROM UnicaenAuth\Entity\Db\CategoriePrivilege cp ORDER BY cp.ordre'; + $query = $this->getEntityManager()->createQuery($dql); + $categories = $query->getResult(); + + return $categories; + } + +} diff --git a/src/UnicaenAuth/Service/PrivilegeService.php b/src/UnicaenAuth/Service/PrivilegeService.php new file mode 100644 index 0000000000000000000000000000000000000000..5ace3b1325cf034b336764ff8dc03f8d29b773fc --- /dev/null +++ b/src/UnicaenAuth/Service/PrivilegeService.php @@ -0,0 +1,127 @@ +<?php + +namespace UnicaenAuth\Service; + +use UnicaenAuth\Entity\Db\Privilege; +use UnicaenAuth\Entity\Db\Role; +use UnicaenAuth\Provider\Privilege\PrivilegeProviderInterface; +use \BjyAuthorize\Provider\Resource\ProviderInterface as ResourceProviderInterface; + +class PrivilegeService extends AbstractService implements PrivilegeProviderInterface, ResourceProviderInterface +{ + /** + * @var array + */ + private $privilegesRoles; + + + + /** + * @return Privilege[] + */ + public function getList() + { + $dql = 'SELECT p, c FROM UnicaenAuth\Entity\Db\Privilege p JOIN p.categorie c ORDER BY c.ordre, p.ordre'; + $query = $this->getEntityManager()->createQuery($dql); + $privileges = $query->getResult(); + + return $privileges; + } + + + + /** + * @param $id + * + * @return null|Privilege + */ + public function get($id) + { + return $this->getEntityManager()->getRepository('UnicaenAuth\Entity\Db\Privilege')->findOneBy(['id' => $id]); + } + + + + /** + * @param Privilege $privilege + * @param Role $role + * + * @throws \Doctrine\DBAL\DBALException + */ + public function addRole(Privilege $privilege, Role $role) + { + $privilege->addRole($role); + $this->getEntityManager()->flush(); + } + + + + /** + * @param Privilege $privilege + * @param Role $role + * + * @throws \Doctrine\DBAL\DBALException + */ + public function removeRole(Privilege $privilege, Role $role) + { + $privilege->removeRole($role); + $this->getEntityManager()->flush(); + } + + + + /** + * Retourne un tableau à deux dimentions composé de chaînes de caractère UNIQUEMENT + * + * Format du tableau : + * [ + * 'privilege_a' => ['role_1', ...], + * 'privilege_b' => ['role_1', 'role_2', ...], + * ] + * + * @return string[][] + */ + public function getPrivilegesRoles() + { + if (null === $this->privilegesRoles) { + $this->privilegesRoles = []; + $dql = ' + SELECT + p, c, r + FROM + UnicaenAuth\Entity\Db\Privilege p + JOIN p.categorie c + JOIN p.role r + '; + $result = $this->getEntityManager()->createQuery($dql)->getResult(); + foreach( $result as $privilege){ + /* @var $privilege Privilege */ + $pr = []; + foreach( $privilege->getRole() as $role ){ + /* @var $role Role */ + $pr[] = $role->getRoleId(); + } + $this->privilegesRoles[$privilege->getFullCode()] = $pr; + } + } + + return $this->privilegesRoles; + } + + + + /** + * @return array + */ + public function getResources() + { + $resources = []; + $privileges = array_keys($this->getPrivilegesRoles()); + foreach ($privileges as $privilege) { + $resources[] = 'privilege/' . $privilege; + } + + return $resources; + } + +} diff --git a/src/UnicaenAuth/Service/RoleService.php b/src/UnicaenAuth/Service/RoleService.php new file mode 100644 index 0000000000000000000000000000000000000000..162042dd9a966908482262f5e73ebbb500355665 --- /dev/null +++ b/src/UnicaenAuth/Service/RoleService.php @@ -0,0 +1,96 @@ +<?php + +namespace UnicaenAuth\Service; + +use Doctrine\Common\Persistence\ObjectRepository; +use UnicaenAuth\Entity\Db\Role; + + +/** + * Class RoleService + * + * @package UnicaenAuth\Service + * @author Laurent LÉCLUSE <laurent.lecluse at unicaen.fr> + */ +class RoleService extends AbstractService +{ + /** + * @return ObjectRepository + */ + public function getRepo() + { + return $this->getEntityManager()->getRepository('UnicaenAuth\Entity\Db\Role'); + } + + + + /** + * @return Role[] + */ + public function getList() + { + $dql = 'SELECT r FROM UnicaenAuth\Entity\Db\Role r ORDER BY r.roleId'; + $query = $this->getEntityManager()->createQuery($dql); + $roles = $query->getResult(); + + return $roles; + } + + + + /** + * @param $id + * + * @return null|Role + */ + public function get($id) + { + return $this->getRepo()->findOneBy(['id' => $id]); + } + + + + /** + * Sauvegarde le rôle en BDD + * + * @param Role $role + * + * @return self + */ + public function save(Role $role) + { + $this->getEntityManager()->persist($role); + $this->getEntityManager()->flush($role); + + return $this; + } + + + + /** + * Supprime un rôle + * + * @param Role $role + * + * @return $this + */ + public function delete(Role $role) + { + $this->getEntityManager()->remove($role); + $this->getEntityManager()->flush($role); + + return $this; + } + + + + /** + * Nouvelle entité + * + * @return Role + */ + public function newEntity() + { + return new Role; + } +} diff --git a/src/UnicaenAuth/Service/Traits/CategoriePrivilegeAwareTrait.php b/src/UnicaenAuth/Service/Traits/CategoriePrivilegeAwareTrait.php new file mode 100644 index 0000000000000000000000000000000000000000..19a75df27609041ec09539138c5c3ae8212b27b5 --- /dev/null +++ b/src/UnicaenAuth/Service/Traits/CategoriePrivilegeAwareTrait.php @@ -0,0 +1,56 @@ +<?php + +namespace UnicaenAuth\Service\Traits; + +use UnicaenAuth\Service\CategoriePrivilegeService; +use RuntimeException; + +/** + * Description of CategoriePrivilegeServiceAwareTrait + * + * @author Laurent LÉCLUSE <laurent.lecluse at unicaen.fr> + */ +trait CategoriePrivilegeServiceAwareTrait +{ + /** + * @var CategoriePrivilegeService + */ + private $serviceCategoriePrivilege; + + + + /** + * @param CategoriePrivilegeService $serviceCategoriePrivilege + * + * @return self + */ + public function setServiceCategoriePrivilege(CategoriePrivilegeService $serviceCategoriePrivilege) + { + $this->serviceCategoriePrivilege = $serviceCategoriePrivilege; + + return $this; + } + + + + /** + * @return CategoriePrivilegeService + * @throws RuntimeException + */ + public function getServiceCategoriePrivilege() + { + if (empty($this->serviceCategoriePrivilege)) { + if (!method_exists($this, 'getServiceLocator')) { + throw new RuntimeException('La classe ' . get_class($this) . ' n\'a pas accès au ServiceLocator.'); + } + + $serviceLocator = $this->getServiceLocator(); + if (method_exists($serviceLocator, 'getServiceLocator')) { + $serviceLocator = $serviceLocator->getServiceLocator(); + } + $this->serviceCategoriePrivilege = $serviceLocator->get('UnicaenAuth\Service\CategoriePrivilege'); + } + + return $this->serviceCategoriePrivilege; + } +} \ No newline at end of file diff --git a/src/UnicaenAuth/Service/Traits/PrivilegeServiceAwareTrait.php b/src/UnicaenAuth/Service/Traits/PrivilegeServiceAwareTrait.php new file mode 100644 index 0000000000000000000000000000000000000000..e26587946fc368239edc38284032fe7b34da1791 --- /dev/null +++ b/src/UnicaenAuth/Service/Traits/PrivilegeServiceAwareTrait.php @@ -0,0 +1,56 @@ +<?php + +namespace UnicaenAuth\Service\Traits; + +use UnicaenAuth\Service\PrivilegeService; +use RuntimeException; + +/** + * Description of PrivilegeServiceAwareTrait + * + * @author Laurent LÉCLUSE <laurent.lecluse at unicaen.fr> + */ +trait PrivilegeServiceAwareTrait +{ + /** + * @var PrivilegeService + */ + private $servicePrivilege; + + + + /** + * @param PrivilegeService $servicePrivilege + * + * @return self + */ + public function setServicePrivilege(PrivilegeService $servicePrivilege) + { + $this->servicePrivilege = $servicePrivilege; + + return $this; + } + + + + /** + * @return PrivilegeService + * @throws RuntimeException + */ + public function getServicePrivilege() + { + if (empty($this->servicePrivilege)) { + if (!method_exists($this, 'getServiceLocator')) { + throw new RuntimeException('La classe ' . get_class($this) . ' n\'a pas accès au ServiceLocator.'); + } + + $serviceLocator = $this->getServiceLocator(); + if (method_exists($serviceLocator, 'getServiceLocator')) { + $serviceLocator = $serviceLocator->getServiceLocator(); + } + $this->servicePrivilege = $serviceLocator->get('UnicaenAuth\Service\Privilege'); + } + + return $this->servicePrivilege; + } +} \ No newline at end of file diff --git a/src/UnicaenAuth/Service/Traits/RoleServiceAwareTrait.php b/src/UnicaenAuth/Service/Traits/RoleServiceAwareTrait.php new file mode 100644 index 0000000000000000000000000000000000000000..57cb0127d2b94f8eb3c4ca1f9b517e620de250ff --- /dev/null +++ b/src/UnicaenAuth/Service/Traits/RoleServiceAwareTrait.php @@ -0,0 +1,56 @@ +<?php + +namespace UnicaenAuth\Service\Traits; + +use UnicaenAuth\Service\RoleService; +use RuntimeException; + +/** + * Description of RoleServiceAwareTrait + * + * @author Laurent LÉCLUSE <laurent.lecluse at unicaen.fr> + */ +trait RoleServiceAwareTrait +{ + /** + * @var RoleService + */ + private $serviceRole; + + + + /** + * @param RoleService $serviceRole + * + * @return self + */ + public function setServiceRole(RoleService $serviceRole) + { + $this->serviceRole = $serviceRole; + + return $this; + } + + + + /** + * @return RoleService + * @throws RuntimeException + */ + public function getServiceRole() + { + if (empty($this->serviceRole)) { + if (!method_exists($this, 'getServiceLocator')) { + throw new RuntimeException('La classe ' . get_class($this) . ' n\'a pas accès au ServiceLocator.'); + } + + $serviceLocator = $this->getServiceLocator(); + if (method_exists($serviceLocator, 'getServiceLocator')) { + $serviceLocator = $serviceLocator->getServiceLocator(); + } + $this->serviceRole = $serviceLocator->get('UnicaenAuth\Service\Role'); + } + + return $this->serviceRole; + } +} \ No newline at end of file diff --git a/src/UnicaenAuth/Service/Traits/UserContextServiceAwareTrait.php b/src/UnicaenAuth/Service/Traits/UserContextServiceAwareTrait.php new file mode 100644 index 0000000000000000000000000000000000000000..8e958bb64091030e493a4658475595ec0e03d294 --- /dev/null +++ b/src/UnicaenAuth/Service/Traits/UserContextServiceAwareTrait.php @@ -0,0 +1,56 @@ +<?php + +namespace UnicaenAuth\Service\Traits; + +use UnicaenAuth\Service\UserContextService; +use RuntimeException; + +/** + * Description of UserContextServiceAwareTrait + * + * @author Laurent LÉCLUSE <laurent.lecluse at unicaen.fr> + */ +trait UserContextServiceAwareTrait +{ + /** + * @var UserContextService + */ + private $serviceUserContext; + + + + /** + * @param UserContextService $serviceUserContext + * + * @return self + */ + public function setServiceUserContext(UserContextService $serviceUserContext) + { + $this->serviceUserContext = $serviceUserContext; + + return $this; + } + + + + /** + * @return UserContextService + * @throws RuntimeException + */ + public function getServiceUserContext() + { + if (empty($this->serviceUserContext)) { + if (!method_exists($this, 'getServiceLocator')) { + throw new RuntimeException('La classe ' . get_class($this) . ' n\'a pas accès au ServiceLocator.'); + } + + $serviceLocator = $this->getServiceLocator(); + if (method_exists($serviceLocator, 'getServiceLocator')) { + $serviceLocator = $serviceLocator->getServiceLocator(); + } + $this->serviceUserContext = $serviceLocator->get('UnicaenAuth\Service\UserContext'); + } + + return $this->serviceUserContext; + } +} \ No newline at end of file diff --git a/src/UnicaenAuth/Service/User.php b/src/UnicaenAuth/Service/User.php index f10946f325bd24eeec67c8db45d43a401bb50a4f..34386146ba75c8191f59034ae83d4a1a82ccd7cf 100644 --- a/src/UnicaenAuth/Service/User.php +++ b/src/UnicaenAuth/Service/User.php @@ -6,6 +6,8 @@ use UnicaenApp\Exception; use UnicaenApp\Mapper\Ldap\People as LdapPeopleMapper; use UnicaenAuth\Options\ModuleOptions; use UnicaenAuth\Event\UserAuthenticatedEvent; +use Zend\ServiceManager\ServiceLocatorAwareInterface; +use Zend\ServiceManager\ServiceLocatorAwareTrait; use Zend\ServiceManager\ServiceManager; use Zend\ServiceManager\ServiceManagerAwareInterface; use Zend\EventManager\EventManagerAwareInterface; @@ -24,14 +26,12 @@ use ZfcUser\Options\ModuleOptions as ZfcUserModuleOptions; * @see \UnicaenAuth\Authentication\Adapter\AbstractFactory * @author Bertrand GAUTHIER <bertrand.gauthier at unicaen.fr> */ -class User implements ServiceManagerAwareInterface, EventManagerAwareInterface +class User implements ServiceLocatorAwareInterface, EventManagerAwareInterface { - const EVENT_USER_AUTHENTICATED_PRE_PERSIST = 'userAuthenticated.prePersist'; + use ServiceLocatorAwareTrait; - /** - * @var ServiceManager - */ - protected $serviceManager; + + const EVENT_USER_AUTHENTICATED_PRE_PERSIST = 'userAuthenticated.prePersist'; /** * @var EventManagerInterface @@ -83,7 +83,7 @@ class User implements ServiceManagerAwareInterface, EventManagerAwareInterface } // update/insert de l'utilisateur dans la table de l'appli - $mapper = $this->getServiceManager()->get('zfcuser_user_mapper'); /* @var $mapper \ZfcUserDoctrineORM\Mapper\User */ + $mapper = $this->getServiceLocator()->get('zfcuser_user_mapper'); /* @var $mapper \ZfcUserDoctrineORM\Mapper\User */ try { $entity = $mapper->findByUsername($username); if (!$entity) { @@ -119,26 +119,6 @@ class User implements ServiceManagerAwareInterface, EventManagerAwareInterface return true; } - /** - * Retrieve service manager instance - * - * @return ServiceManager - */ - public function getServiceManager() - { - return $this->serviceManager; - } - - /** - * Set service manager - * - * @param ServiceManager $serviceManager - */ - public function setServiceManager(ServiceManager $serviceManager) - { - $this->serviceManager = $serviceManager; - return $this; - } /** * Retrieve the event manager @@ -176,7 +156,7 @@ class User implements ServiceManagerAwareInterface, EventManagerAwareInterface public function getLdapPeopleMapper() { if (null === $this->ldapPeopleMapper) { - $this->ldapPeopleMapper = $this->getServiceManager()->get('ldap_people_mapper'); + $this->ldapPeopleMapper = $this->getServiceLocator()->get('ldap_people_mapper'); } return $this->ldapPeopleMapper; } @@ -208,7 +188,7 @@ class User implements ServiceManagerAwareInterface, EventManagerAwareInterface public function getOptions() { if (!$this->options instanceof ModuleOptions) { - $this->setOptions($this->getServiceManager()->get('unicaen-auth_module_options')); + $this->setOptions($this->getServiceLocator()->get('unicaen-auth_module_options')); } return $this->options; } diff --git a/src/UnicaenAuth/Service/UserContext.php b/src/UnicaenAuth/Service/UserContext.php index df9d395f9be8bca632b151a68d1262377df8fa15..a07398f34d6b3290be1bd3a28a6b5d49ac5ff19a 100644 --- a/src/UnicaenAuth/Service/UserContext.php +++ b/src/UnicaenAuth/Service/UserContext.php @@ -3,8 +3,7 @@ namespace UnicaenAuth\Service; use UnicaenApp\Exception\RuntimeException; -use Zend\ServiceManager\ServiceLocatorAwareInterface; -use Zend\ServiceManager\ServiceLocatorAwareTrait; +use UnicaenApp\Traits\SessionContainerTrait; use Zend\Session\Container as SessionContainer; use Zend\Permissions\Acl\Role\RoleInterface; use ZfcUser\Entity\UserInterface; @@ -16,9 +15,9 @@ use UnicaenAuth\Acl\NamedRole; * * @author Laurent LÉCLUSE <laurent.lecluse at unicaen.fr> */ -class UserContext implements ServiceLocatorAwareInterface +class UserContext extends AbstractService { - use ServiceLocatorAwareTrait; + use SessionContainerTrait; /** * @var mixed @@ -30,10 +29,7 @@ class UserContext implements ServiceLocatorAwareInterface */ protected $identityRoles; - /** - * @var SessionContainer - */ - protected $sessionContainer; + /** * Retourne l'utilisateur BDD courant @@ -51,6 +47,8 @@ class UserContext implements ServiceLocatorAwareInterface return null; } + + /** * Retourne l'utilisateur LDAP courant * @@ -67,6 +65,8 @@ class UserContext implements ServiceLocatorAwareInterface return null; } + + /** * Retourne les données d'identité correspondant à l'utilisateur courant. * @@ -84,6 +84,8 @@ class UserContext implements ServiceLocatorAwareInterface return $this->identity; } + + /** * Retourne tous les rôles de l'utilisateur courant, pas seulement le rôle courant sélectionné. * @@ -92,13 +94,15 @@ class UserContext implements ServiceLocatorAwareInterface public function getIdentityRoles() { if (null === $this->identityRoles) { - $identityProvider = $this->getIdentityProvider(); + $identityProvider = $this->getIdentityProvider(); $this->identityRoles = $identityProvider->getAllIdentityRoles(); } return $this->identityRoles; } + + /** * Retourne parmi tous les rôles de l'utilisateur courant ceux qui peuvent être sélectionnés. * @@ -106,12 +110,16 @@ class UserContext implements ServiceLocatorAwareInterface */ public function getSelectableIdentityRoles() { - $filter = function($r) { return !($r instanceof NamedRole && !$r->getSelectable()); }; + $filter = function ($r) { + return !($r instanceof NamedRole && !$r->getSelectable()); + }; $roles = array_filter($this->getIdentityRoles(), $filter); return $roles; } + + /** * Si un utilisateur est authentifié, retourne le rôle utilisateur sélectionné, * ou alors le premier sélectionnable si aucun n'a été sélectionné. @@ -134,20 +142,25 @@ class UserContext implements ServiceLocatorAwareInterface $roleId = $this->getSessionContainer()->selectedIdentityRole; - $role = $this->normalizedIdentityRole($roleId); - if ($this->isRoleValid($role)) { - return $role; + if ($roleId){ + $role = $this->normalizedIdentityRole($roleId); + if ($this->isRoleValid($role)) { + return $role; + } } return null; } + + /** * Mémorise en session le rôle spécifié comme étant le rôle courant de l'utilisateur. * * NB: seul l'id du rôle est mémorisé en session. * * @param RoleInterface|string $role + * * @return \UnicaenAuth\Service\UserContext * @throws RuntimeException */ @@ -161,30 +174,34 @@ class UserContext implements ServiceLocatorAwareInterface $role = $role->getRoleId(); } $this->getSessionContainer()->selectedIdentityRole = $role; - } - else { + } else { unset($this->getSessionContainer()->selectedIdentityRole); } return $this; } + + /** * Retourne l'éventuel rôle spécifié en session devant être le prochain rôle sélectionné. * * @return string|null */ - private function getNextSelectedIdentityRole() + public function getNextSelectedIdentityRole() { return $this->getSessionContainer()->nextSelectedIdentityRole; } + + /** * Mémorise en session le rôle devant être le prochain rôle sélectionné. * * NB: seul l'id du rôle est mémorisé en session ; la durée de vie du stockage est de 1 requête seulement. * * @param RoleInterface|string $role + * * @return \UnicaenAuth\Service\UserContext */ public function setNextSelectedIdentityRole($role) @@ -196,19 +213,20 @@ class UserContext implements ServiceLocatorAwareInterface if ($role) { $this->getSessionContainer()->nextSelectedIdentityRole = $role; $this->getSessionContainer()->setExpirationHops(1, 'nextSelectedIdentityRole'); - - } - else { + } else { unset($this->getSessionContainer()->nextSelectedIdentityRole); } return $this; } + + /** * Recherche le role spécifié parmi les rôles connus au format objets. * * @param RoleInterface|string $role + * * @return RoleInterface Role trouvé au format objet dans la mesure du possible */ protected function normalizedIdentityRole($role) @@ -229,10 +247,13 @@ class UserContext implements ServiceLocatorAwareInterface return $role; } + + /** * Teste si le rôle spécifié fait partie des rôles disponibles. * * @param RoleInterface|string $role + * * @return boolean */ protected function isRoleValid($role) @@ -253,29 +274,16 @@ class UserContext implements ServiceLocatorAwareInterface return false; } + + /** * * @return \UnicaenAuth\Provider\Identity\Chain */ private function getIdentityProvider() { - $authorize = $this->getServiceLocator()->get('BjyAuthorize\Service\Authorize'); - - return $authorize->getIdentityProvider(); /* @var $identityProvider \UnicaenAuth\Provider\Identity\Chain */ + return $this->getServiceAuthorize()->getIdentityProvider(); + /* @var $identityProvider \UnicaenAuth\Provider\Identity\Chain */ } - /** - * Retourne le stockage en session utilisé pour mémoriser le profil - * sélectionné par l'utilsateur. - * - * @return SessionContainer - */ - protected function getSessionContainer() - { - if (null === $this->sessionContainer) { - $this->sessionContainer = new SessionContainer(get_class()); - } - - return $this->sessionContainer; - } } \ No newline at end of file diff --git a/view/unicaen-auth/droits/index.phtml b/view/unicaen-auth/droits/index.phtml new file mode 100644 index 0000000000000000000000000000000000000000..3f1837029d85638dbe083abc02a1604922b43bf9 --- /dev/null +++ b/view/unicaen-auth/droits/index.phtml @@ -0,0 +1,34 @@ +<?php + +use UnicaenAuth\Provider\Privilege\Privileges; + +$canViewRoles = $this->isAllowed(Privileges::getResource(Privileges::DROIT_ROLE_VISUALISATION)); +$canViewPrivileges = $this->isAllowed(Privileges::getResource(Privileges::DROIT_PRIVILEGE_VISUALISATION)); + +?> +<h1 class="page-header">Gestion des droits d'accès</h1> + +<dl> + <?php if ($canViewRoles): ?> + <dt><a href="<?php echo $this->url('droits/roles') ?>">Gestion des rôles</a></dt> + <dd> + Permet de visualiser les rôles existants. Permet également de les modifier, + d'en ajouter ou d'en supprimer si vous avez les droits requis pour cela. + </dd> + <?php endif; ?> + + <?php if ($canViewPrivileges): ?> + <dt><a href="<?php echo $this->url('droits/privileges') ?>">Gestion des privilèges</a></dt> + <dd> + Tableau de bord listant, par rôle, les privilèges qui lui sont accordés. + Le tableau permet également, si vous en avez le droit, de modifier les privilèges accordés par rôle. + </dd> + <?php endif; ?> +</dl> +<style> + + dt { + padding-top: 2em; + } + +</style> \ No newline at end of file diff --git a/view/unicaen-auth/droits/partial/tbl-link.phtml b/view/unicaen-auth/droits/partial/tbl-link.phtml new file mode 100644 index 0000000000000000000000000000000000000000..254869740a36ce298fed47e73d8d0bb72ea6adff --- /dev/null +++ b/view/unicaen-auth/droits/partial/tbl-link.phtml @@ -0,0 +1,23 @@ +<?php + +use UnicaenAuth\Provider\Privilege\Privileges; + +/* @var $role UnicaenAuth\Entity\Db\Role */ +/* @var $privilege UnicaenAuth\Entity\Db\Privilege */ + +$canEdit = $this->isAllowed('privilege/'.Privileges::DROIT_PRIVILEGE_EDITION); + +if ($privilege->getRole()->contains($role)): +?> + + <?php if ($canEdit): ?><a href="javascript:void(0)" data-action="refuser" title="Privilège accordé. Cliquez pour le retirer."><?php endif; ?> + <span class="glyphicon glyphicon-ok text-success"></span> + <?php if ($canEdit): ?></a><?php endif; ?> + +<?php else: ?> + + <?php if ($canEdit): ?><a href="javascript:void(0)" data-action="accorder" title="Privilège refusé. Cliquez pour l'accorder."><?php endif; ?> + <span class="glyphicon glyphicon-remove text-danger refuse"></span> + <?php if ($canEdit): ?></a><?php endif; ?> + +<?php endif; ?> \ No newline at end of file diff --git a/view/unicaen-auth/droits/privileges-modifier.phtml b/view/unicaen-auth/droits/privileges-modifier.phtml new file mode 100644 index 0000000000000000000000000000000000000000..1e994398040b46a1831413f46409f62ad1e564e2 --- /dev/null +++ b/view/unicaen-auth/droits/privileges-modifier.phtml @@ -0,0 +1,9 @@ +<?php + +/* @var $role UnicaenAuth\Entity\Db\Role */ +/* @var $privilege UnicaenAuth\Entity\Db\Privilege */ + +echo $this->partial( + '/unicaen-auth/droits/partial/tbl-link', + compact('role','privilege') + ); \ No newline at end of file diff --git a/view/unicaen-auth/droits/privileges.phtml b/view/unicaen-auth/droits/privileges.phtml new file mode 100644 index 0000000000000000000000000000000000000000..8ce8e3ec1786b06180d441b15e77a29a045addf6 --- /dev/null +++ b/view/unicaen-auth/droits/privileges.phtml @@ -0,0 +1,152 @@ +<?php + +/* @var $privileges UnicaenAuth\Entity\Db\Privilege[] */ +/* @var $roles UnicaenAuth\Entity\Db\Role[] */ + +?> +<h1 class="page-header">Gestion des privilèges</h1> + +<table class="droits-tbl table table-hover table-bordered table-condensed table-extra-condensed table-header-rotated" data-modifier-url="<?php echo $this->url('droits/privileges/modifier'); ?>"> +<thead> + <tr> + <th class="separator"></th> + <?php $first = true; foreach( $roles as $role ):?> + <th class="rotate-45" title="<?php echo $role; ?>"><div<?php if ($first) echo ' class="first"'; ?>><span><?php echo $role; ?></span></div></th> + <?php $first = false; endforeach; ?> + </tr> + <tr> + <th>Privilèges</th> + <th colspan="<?php echo count($roles); ?>">Rôles</th> + <th style="border:none;min-width:166px"> </th> + </tr> +</thead> +<tbody> +<?php foreach( $privileges as $cat ): ?> + <tr> + <th class="separator"> </th> + <th class="separator" colspan="<?php echo 1 + count($roles); ?>"><?php echo $cat['categorie'] ?></th> + </tr> + <?php foreach( $cat['privileges'] as $privilege ): ?> + <tr> + <th class="privilege"><?php echo $privilege ?></th> + <?php $statut=null; foreach( $roles as $role ): ?> + <td class="modifier" data-role="<?php echo $role->getId() ?>" data-privilege="<?php echo $privilege->getId() ?>"> + <?php echo $this->partial( '/unicaen-auth/droits/partial/tbl-link', compact('role','privilege')) ?> + </td> + <?php endforeach; ?> + </tr> + <?php endforeach; ?> +<?php endforeach; ?> +</tbody> +</table> +<script> + $(function () + { + $.widget("ose.droitsTbl", { + + modifier: function (td, action) + { + var that = this; + td.html("<div class=\"loading\"> </div>"); + td.load(this.element.data('modifier-url'), { + role: td.data("role"), + statut: td.data("statut"), + privilege: td.data("privilege"), + action: action + }, function () + { + that.initModifierClick(td); // pour reconnecter l'action du lien... + }); + + }, + + + initModifierClick: function (td) + { + var that = this; + td.find("a").on("click", function () + { + that.modifier(td, $(this).data("action")); + }); + }, + + _create: function () + { + var that = this; + this.element.find("td.modifier").each(function () + { + that.initModifierClick($(this)); + }); + } + }); + + WidgetInitializer.add('droits-tbl', 'droitsTbl'); + }); + +</script> +<style> + + .table-header-rotated th.row-header { + width: auto; + + } + + .table-header-rotated td { + width: 40px; + vertical-align: middle; + text-align: center; + } + + .table-header-rotated th.rotate-45 { + border: none; + height: 200px; + width: 40px; + min-width: 40px; + max-width: 40px; + position: relative; + vertical-align: bottom; + padding: 0; + line-height: 1; + white-space: nowrap; + } + + .table-header-rotated th.rotate-45 > div { + position: relative; + top: 0px; + left: 83px; + height: 100%; + transform: skew(-40deg, 0deg); + overflow: hidden; + border-right: 1px solid #ddd; + } + + .table-header-rotated th.rotate-45 > div.first { + border-left: 1px solid #ddd; + } + + .table-header-rotated th.rotate-45 span { + transform: skew(40deg, 0deg) rotate(310deg); + position: absolute; + bottom: 40px; + left: -30px; + display: inline-block; + width: 100px; + text-align: left; + } + + .table-header-rotated .separator { + border: none; + } + + .droits-tbl th.privilege { + min-width: 200px; + max-width: 200px; + width: 200px; + } + + .droits-tbl td span.refuse { + opacity: 0.5; + } + + +</style> \ No newline at end of file diff --git a/view/unicaen-auth/droits/role-edition.phtml b/view/unicaen-auth/droits/role-edition.phtml new file mode 100644 index 0000000000000000000000000000000000000000..e7699d422c69ab4815f80eb41cb04da64706147a --- /dev/null +++ b/view/unicaen-auth/droits/role-edition.phtml @@ -0,0 +1,19 @@ +<?php + +/* @var $form Application\Form\Gestion\RoleForm */ +/* @var $errors array */ + + +echo $this->form()->openTag($form->prepare()); + +if ($errors) { + echo $this->messenger()->setMessages([UnicaenApp\View\Helper\Messenger::ERROR => $errors]); +} + +echo $this->formControlGroup($form->get('role-id')); +echo $this->formControlGroup($form->get('parent')); +echo $this->formControlGroup($form->get('ldap-filter')); +echo $this->formRow($form->get('submit')); +echo $this->formHidden($form->get('id')); + +echo $this->form()->closeTag(); \ No newline at end of file diff --git a/view/unicaen-auth/droits/role-suppression.phtml b/view/unicaen-auth/droits/role-suppression.phtml new file mode 100644 index 0000000000000000000000000000000000000000..9939d8dae5237d0392f7437998c4289771468728 --- /dev/null +++ b/view/unicaen-auth/droits/role-suppression.phtml @@ -0,0 +1,12 @@ +<?php +if (isset($errors) && $errors) { + echo $this->messenger()->setMessages([UnicaenApp\View\Helper\Messenger::ERROR => $errors]); +} +else { + echo '<p class="lead text-danger"><strong>Attention!</strong> Confirmez-vous la suppression du rôle '.$role.' ?</p>'; + + echo $this->form()->openTag($form); + echo $this->formHidden($form->get('id')); + echo $this->formSubmit($form->get('submit')->setAttribute('class', 'btn btn-primary')); + echo $this->form()->closeTag(); +} \ No newline at end of file diff --git a/view/unicaen-auth/droits/roles.phtml b/view/unicaen-auth/droits/roles.phtml new file mode 100644 index 0000000000000000000000000000000000000000..ed85487cd53eff421b4fcc818b7620b4970301e9 --- /dev/null +++ b/view/unicaen-auth/droits/roles.phtml @@ -0,0 +1,50 @@ +<h1 class="page-header">Gestion des rôles</h1> +<?php + +use UnicaenAuth\Provider\Privilege\Privileges; + +/* @var $roles UnicaenAuth\Entity\Db\Role[] */ + +$canEdit = $this->isAllowed('privilege/'.Privileges::DROIT_ROLE_EDITION); +$ajoutUrl = $this->url( 'droits/roles/edition' ); + +?> +<table class="table table-condensed table-bordered"> + <tr> + <th>Nom</th> + <th>Parent</th> + <th>Filtre LDAP</th> + <?php if ($canEdit): ?><th>Action</th><?php endif; ?> + </tr> +<?php foreach( $roles as $role ): + $editionUrl = $this->url( 'droits/roles/edition', ['role' => $role->getId()] ); + $suppressionUrl = $this->url( 'droits/roles/suppression', ['role' => $role->getId()] ); +?> + <tr> + <td><?php echo $role->getRoleId(); ?></td> + <td><?php echo $role->getParent(); ?></td> + <td><?php echo $role->getLdapFilter(); ?></td> + <?php if ($canEdit): ?> + <td style="width:1%;white-space: nowrap;text-align: center"> + <a href="<?php echo $editionUrl; ?>" class="ajax-modal" data-event="role-edition"><span class="glyphicon glyphicon-edit"></span></a> + <a href="<?php echo $suppressionUrl; ?>" class="ajax-modal" data-event="role-suppression"><span class="glyphicon glyphicon-remove"></span></a> + </td> + <?php endif; ?> + </tr> +<?php endforeach; ?> +</table> +<?php if ($canEdit): // droits ?> +<a href="<?php echo $ajoutUrl ?>" class="btn btn-primary ajax-modal" data-event="role-edition">Création d'un nouveau rôle</a> +<?php endif; ?> +<?php echo $this->modalAjaxDialog('roles-edition-suppression'); ?> +<script type="text/javascript"> + $(function() { + $("body").on("role-edition", function(event, data) { + window.location.reload(); + }); + + $("body").on("role-suppression", function(event, data) { + window.location.reload(); + }); + }); +</script> \ No newline at end of file