diff --git a/.gitignore b/.gitignore index ae09aba9b8e074dcf3c14bed38dc34c336d4c83a..31e3ac6d8150c272dbb855c640aaa3f34eefe3b7 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,2 @@ vendor/ -.idea \ No newline at end of file +.idea diff --git a/Module.php b/Module.php index b4d473d542f12285e9069d7bd8f8b0f91de28e80..1d540cb5e06e683237ca6a8145e919c343d4cba3 100644 --- a/Module.php +++ b/Module.php @@ -2,9 +2,18 @@ namespace UnicaenAuth; +use UnicaenAuth\Authentication\Adapter\Cas as CasAdapter; +use UnicaenAuth\Options\ModuleOptions; +use UnicaenAuth\Service\ShibService; +use Zend\EventManager\EventInterface; use Zend\ModuleManager\Feature\AutoloaderProviderInterface; use Zend\ModuleManager\Feature\ConfigProviderInterface; use Zend\ModuleManager\Feature\ServiceProviderInterface; +use Zend\ServiceManager\Exception\ServiceNotFoundException; +use Zend\ServiceManager\ServiceLocatorInterface; +use Zend\View\Helper\Navigation; +use ZfcUser\Form\Login; +use ZfcUser\Form\LoginFilter; /** * Point d'entrée du module d'authentification Unicaen. @@ -14,7 +23,11 @@ use Zend\ModuleManager\Feature\ServiceProviderInterface; class Module implements AutoloaderProviderInterface, ConfigProviderInterface, ServiceProviderInterface { /** - * + * @var ModuleOptions + */ + private $options; + + /** * @return array * @see ConfigProviderInterface */ @@ -23,10 +36,7 @@ class Module implements AutoloaderProviderInterface, ConfigProviderInterface, Se return include __DIR__ . '/config/module.config.php'; } - - /** - * * @return array * @see AutoloaderProviderInterface */ @@ -44,8 +54,6 @@ class Module implements AutoloaderProviderInterface, ConfigProviderInterface, Se ]; } - - /** * This method is called once the MVC bootstrapping is complete, * after the "loadModule.post" event, once $application->bootstrap() is called. @@ -54,9 +62,9 @@ class Module implements AutoloaderProviderInterface, ConfigProviderInterface, Se * * @see BootstrapListenerInterface */ - public function onBootstrap(\Zend\EventManager\EventInterface $e) - /* @var \Zend\Mvc\MvcEvent $e */ + public function onBootstrap(EventInterface $e) { + /* @var \Zend\Mvc\MvcEvent $e */ $application = $e->getApplication(); /* @var $services \Zend\ServiceManager\ServiceManager */ $services = $application->getServiceManager(); @@ -65,63 +73,45 @@ class Module implements AutoloaderProviderInterface, ConfigProviderInterface, Se try { $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) { + Navigation::setDefaultAcl($authorizeService->getAcl()); + Navigation::setDefaultRole($authorizeService->getIdentity()); + } catch (ServiceNotFoundException $snfe) { // pas de module BjyAuthorize : pas d'ACL } - /* @var $options Options\ModuleOptions */ - $options = $services->get('unicaen-auth_module_options'); + /* @var $options ModuleOptions */ + $this->options = $services->get('unicaen-auth_module_options'); - // si l'auth CAS est demandée, modif de la route de connexion pour zapper le formulaire - if ($options->getCas() && php_sapi_name() !== 'cli') { - /* @var $router \Zend\Mvc\Router\Http\TreeRouteStack */ - $router = $services->get('router'); - $router->addRoutes([ - // remplace les routes existantes (cf. config du module) - 'zfcuser' => [ - 'type' => 'Literal', - 'priority' => 1000, - 'options' => [ - 'route' => '/auth', - 'defaults' => [ - 'controller' => 'zfcuser', - 'action' => 'index', - ], - ], - 'may_terminate' => true, - 'child_routes' => [ - 'login' => [ - 'type' => 'Literal', - 'options' => [ - 'route' => '/connexion', - 'defaults' => [ - 'controller' => 'zfcuser', - 'action' => 'authenticate', // zappe l'action 'login' - ], - ], - ], - 'logout' => [ - 'type' => 'Literal', - 'options' => [ - 'route' => '/deconnexion', - 'defaults' => [ - 'controller' => 'zfcuser', - 'action' => 'logout', - ], - ], - ], - ], - ], - ]); - } + $this->reconfigureRoutesForAuth($services); } + /** + * @param ServiceLocatorInterface $sl + */ + private function reconfigureRoutesForAuth(ServiceLocatorInterface $sl) + { + /* @var $router \Zend\Mvc\Router\Http\TreeRouteStack */ + $router = $sl->get('router'); + + // si l'auth CAS est activée, modif de la route de connexion pour zapper le formulaire d'auth maison. + $isCasEnable = (bool) $this->options->getCas(); + if ($isCasEnable && php_sapi_name() !== 'cli') { + /** @var CasAdapter $casAdapter */ + $casAdapter = $sl->get('UnicaenAuth\Authentication\Adapter\Cas'); + $casAdapter->reconfigureRoutesForCasAuth($router); + } + // si l'auth Shibboleth est activée, modif de la route de déconnexion pour réaliser la déconnexion Shibboleth. + $shibOptions = $this->options->getShibboleth(); + $isShibEnable = array_key_exists('enable', $shibOptions) && (bool) $shibOptions['enable']; + if ($isShibEnable && php_sapi_name() !== 'cli') { + /** @var ShibService $shibService */ + $shibService = $sl->get(ShibService::class); + $shibService->reconfigureRoutesForShibAuth($router); + } + } /** - * * @return array * @see ServiceProviderInterface */ @@ -132,8 +122,8 @@ class Module implements AutoloaderProviderInterface, ConfigProviderInterface, Se // verrue pour forcer le label de l'identifiant qqsoit l'options 'auth_identity_fields' 'zfcuser_login_form' => function ($sm) { $options = $sm->get('zfcuser_module_options'); - $form = new \ZfcUser\Form\Login(null, $options); - $form->setInputFilter(new \ZfcUser\Form\LoginFilter($options)); + $form = new Login(null, $options); + $form->setInputFilter(new LoginFilter($options)); $form->get('identity')->setLabel("Username"); return $form; diff --git a/composer.json b/composer.json index b99ab199205eda21d92e32650ded4c7453294edc..268376b2ae1fe029744bc10416b77211a47d0784 100644 --- a/composer.json +++ b/composer.json @@ -4,7 +4,7 @@ "repositories": [ { "type": "composer", - "url": "https://dev.unicaen.fr/packagist" + "url": "https://gest.unicaen.fr/packagist" } ], "require": { diff --git a/config/module.config.php b/config/module.config.php index e0b80300c8d283b25ad59329c73f5392020f7b84..b0b657e3907434f6cebed79bfc97db4978ac5944 100644 --- a/config/module.config.php +++ b/config/module.config.php @@ -1,9 +1,11 @@ <?php -use UnicaenAuth\Provider\Privilege\Privileges; +use UnicaenAuth\Controller\AuthControllerFactory; +use UnicaenAuth\Service\ShibService; +use UnicaenAuth\Service\ShibServiceFactory; +use UnicaenAuth\View\Helper\ShibConnectViewHelperFactory; $settings = [ - /** * Fournisseurs d'identité. */ @@ -119,6 +121,8 @@ return [ ['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' => 'UnicaenAuth\Controller\Auth', 'action' => 'shibboleth', 'roles' => []], ], ], ], @@ -167,6 +171,27 @@ return [ ], 'router' => [ 'routes' => [ + 'auth' => [ + 'type' => 'Literal', + 'options' => [ + 'route' => '/auth', + 'defaults' => [ + 'controller' => 'UnicaenAuth\Controller\Auth', + ], + ], + 'may_terminate' => false, + 'child_routes' => [ + 'shibboleth' => [ + 'type' => 'Literal', + 'options' => [ + 'route' => '/shibboleth', + 'defaults' => [ + 'action' => 'shibboleth', + ], + ], + ], + ], + ], 'zfcuser' => [ 'type' => 'Literal', 'priority' => 1000, @@ -346,12 +371,11 @@ return [ 'invokables' => [ 'UnicaenAuth\Authentication\Storage\Db' => 'UnicaenAuth\Authentication\Storage\Db', 'UnicaenAuth\Authentication\Storage\Ldap' => 'UnicaenAuth\Authentication\Storage\Ldap', + 'UnicaenAuth\Authentication\Storage\Shib' => 'UnicaenAuth\Authentication\Storage\Shib', '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', @@ -367,8 +391,11 @@ return [ 'UnicaenAuth\Provider\Role\Config' => 'UnicaenAuth\Provider\Role\ConfigServiceFactory', 'UnicaenAuth\Provider\Role\DbRole' => 'UnicaenAuth\Provider\Role\DbRoleServiceFactory', 'UnicaenAuth\Provider\Role\Username' => 'UnicaenAuth\Provider\Role\UsernameServiceFactory', + 'UnicaenAuth\Service\Role' => 'UnicaenAuth\Service\RoleServiceFactory', + 'UnicaenAuth\Service\Privilege' => 'UnicaenAuth\Service\PrivilegeServiceFactory', 'BjyAuthorize\Service\Authorize' => 'UnicaenAuth\Service\AuthorizeServiceFactory', // substituion 'zfcuser_redirect_callback' => 'UnicaenAuth\Authentication\RedirectCallbackFactory', // substituion + ShibService::class => ShibServiceFactory::class, 'MouchardCompleterAuth' => 'UnicaenAuth\Mouchard\MouchardCompleterAuthFactory', ], 'shared' => [ @@ -384,6 +411,9 @@ return [ 'UnicaenAuth\Controller\Utilisateur' => 'UnicaenAuth\Controller\UtilisateurController', 'UnicaenAuth\Controller\Droits' => 'UnicaenAuth\Controller\DroitsController', ], + 'factories' => [ + 'UnicaenAuth\Controller\Auth' => AuthControllerFactory::class, + ], ], 'form_elements' => [ @@ -401,6 +431,7 @@ return [ 'userInfo' => 'UnicaenAuth\View\Helper\UserInfoFactory', 'userProfileSelect' => 'UnicaenAuth\View\Helper\UserProfileSelectFactory', 'userProfileSelectRadioItem' => 'UnicaenAuth\View\Helper\UserProfileSelectRadioItemFactory', + 'shibConnect' => ShibConnectViewHelperFactory::class, ], 'invokables' => [ 'appConnection' => 'UnicaenAuth\View\Helper\AppConnection', diff --git a/config/unicaen-auth.global.php.dist b/config/unicaen-auth.global.php.dist index 675d7624589561e4ddc79e5c03e0065483533a6d..4e857772af6eeb5884f556fcd8bc19884ec7f00f 100644 --- a/config/unicaen-auth.global.php.dist +++ b/config/unicaen-auth.global.php.dist @@ -67,6 +67,20 @@ $config = [ if ($settings['enable_privileges']) { $privileges = [ + 'unicaen-auth' => [ + /** + * Classes représentant les entités rôle et privilège. + * - Entité rôle : héritant de \UnicaenAuth\Entity\Db\AbstractRole ou implémentant \UnicaenAuth\Entity\Db\RoleInterface. + * - Entité privilège : héritant de \UnicaenAuth\Entity\Db\AbstractPrivilege ou implémentant \UnicaenAuth\Entity\Db\PrivilegeInterface. + * + * Valeurs par défaut : + * - 'role_entity_class' : 'UnicaenAuth\Entity\Db\Role' + * - 'privilege_entity_class' : 'UnicaenAuth\Entity\Db\Privilege' + */ + 'role_entity_class' => 'UnicaenAuth\Entity\Db\Role', + 'privilege_entity_class' => 'UnicaenAuth\Entity\Db\Privilege', + ], + 'bjyauthorize' => [ 'resource_providers' => [ diff --git a/config/unicaen-auth.local.php.dist b/config/unicaen-auth.local.php.dist index ee3a26e23473b2c52fa32def0ef683adf5c31a57..8cecd5de4426a9112b652beb74c454e0e88c31fe 100644 --- a/config/unicaen-auth.local.php.dist +++ b/config/unicaen-auth.local.php.dist @@ -6,6 +6,12 @@ * drop this config file in it and change the values as you wish. */ $settings = [ + /** + * Activation ou non de l'authentification Shibboleth. + */ + 'shibboleth' => [ + 'enable' => false, + ], /** * Paramètres de connexion au serveur CAS : * - pour désactiver l'authentification CAS, le tableau 'cas' doit être vide. diff --git a/src/UnicaenAuth/Authentication/Adapter/AbstractFactory.php b/src/UnicaenAuth/Authentication/Adapter/AbstractFactory.php index adb8ac15b482a3ed99e54e9b4fe1c2407876d7f7..d5ce3734895e54b34a65aa6f602008f194ccd5df 100644 --- a/src/UnicaenAuth/Authentication/Adapter/AbstractFactory.php +++ b/src/UnicaenAuth/Authentication/Adapter/AbstractFactory.php @@ -1,10 +1,10 @@ <?php + namespace UnicaenAuth\Authentication\Adapter; -use UnicaenApp\Exception; -use UnicaenAuth\Authentication\Adapter\Cas; -use UnicaenAuth\Authentication\Adapter\Db; -use UnicaenAuth\Authentication\Adapter\Ldap; +use UnicaenApp\Exception\LogicException; +use Zend\EventManager\EventManager; +use Zend\EventManager\EventManagerAwareInterface; use Zend\ServiceManager\AbstractFactoryInterface; use Zend\ServiceManager\ServiceLocatorInterface; @@ -34,7 +34,7 @@ class AbstractFactory implements AbstractFactoryInterface * @param ServiceLocatorInterface $serviceLocator * @param $name * @param $requestedName - * @return mixed + * @return \ZfcUser\Authentication\Adapter\AbstractAdapter */ public function createServiceWithName(ServiceLocatorInterface $serviceLocator, $name, $requestedName) { @@ -48,12 +48,19 @@ class AbstractFactory implements AbstractFactoryInterface case __NAMESPACE__ . '\Cas': $adapter = new Cas(); break; + // + // NB: pour faire simple, la stratégie de créer un adapter pour l'auth Shibboleth n'a pas été retenue. + // + // case __NAMESPACE__ . '\Shib': + // $adapter = new Shib(); + // break; default: - throw new Exception("Service demandé inattendu : '$requestedName'!"); + throw new LogicException("Service demandé inattendu : '$requestedName'!"); break; } - if ($adapter instanceof \Zend\EventManager\EventManagerAwareInterface) { + if ($adapter instanceof EventManagerAwareInterface) { + /** @var EventManager $eventManager */ $eventManager = $serviceLocator->get('event_manager'); $adapter->setEventManager($eventManager); $userService = $serviceLocator->get('unicaen-auth_user_service'); /* @var $userService \UnicaenAuth\Service\User */ diff --git a/src/UnicaenAuth/Authentication/Adapter/Cas.php b/src/UnicaenAuth/Authentication/Adapter/Cas.php index 5c3a20343e21b3fc57c1dd624ac96541e50d915e..98d563a6ba7bcdd5dc4055d40e1021118ac46526 100644 --- a/src/UnicaenAuth/Authentication/Adapter/Cas.php +++ b/src/UnicaenAuth/Authentication/Adapter/Cas.php @@ -9,6 +9,7 @@ use Zend\Authentication\Result as AuthenticationResult; use Zend\EventManager\EventManager; use Zend\EventManager\EventManagerAwareInterface; use Zend\EventManager\EventManagerInterface; +use Zend\Mvc\Router\Http\TreeRouteStack; use Zend\ServiceManager\ServiceManager; use Zend\ServiceManager\ServiceManagerAwareInterface; use ZfcUser\Authentication\Adapter\AbstractAdapter; @@ -230,4 +231,48 @@ class Cas extends AbstractAdapter implements ServiceManagerAwareInterface, Event $this->eventManager = $eventManager; return $this; } + + /** + * @param TreeRouteStack $router + */ + public function reconfigureRoutesForCasAuth(TreeRouteStack $router) + { + $router->addRoutes([ + // remplace les routes existantes (cf. config du module) + 'zfcuser' => [ + 'type' => 'Literal', + 'priority' => 1000, + 'options' => [ + 'route' => '/auth', + 'defaults' => [ + 'controller' => 'zfcuser', + 'action' => 'index', + ], + ], + 'may_terminate' => true, + 'child_routes' => [ + 'login' => [ + 'type' => 'Literal', + 'options' => [ + 'route' => '/connexion', + 'defaults' => [ + 'controller' => 'zfcuser', + 'action' => 'authenticate', // zappe l'action 'login' + ], + ], + ], + 'logout' => [ + 'type' => 'Literal', + 'options' => [ + 'route' => '/deconnexion', + 'defaults' => [ + 'controller' => 'zfcuser', + 'action' => 'logout', + ], + ], + ], + ], + ], + ]); + } } \ No newline at end of file diff --git a/src/UnicaenAuth/Authentication/Adapter/Ldap.php b/src/UnicaenAuth/Authentication/Adapter/Ldap.php index e26828192027e2e1546ecf0589e66dd776e8070d..630f9e0c66d35ebe49b2cebb4d0d94f023f4a58d 100644 --- a/src/UnicaenAuth/Authentication/Adapter/Ldap.php +++ b/src/UnicaenAuth/Authentication/Adapter/Ldap.php @@ -1,16 +1,17 @@ <?php + namespace UnicaenAuth\Authentication\Adapter; +use UnicaenApp\Exception\RuntimeException; +use UnicaenApp\Mapper\Ldap\People as LdapPeopleMapper; use UnicaenAuth\Options\ModuleOptions; -use Zend\Authentication\Exception\UnexpectedValueException; -use Zend\Authentication\Result as AuthenticationResult; +use UnicaenAuth\Service\User; use Zend\Authentication\Adapter\Ldap as LdapAuthAdapter; -use Zend\Authentication\Result; -use Zend\EventManager\Event; +use Zend\Authentication\Exception\ExceptionInterface; +use Zend\Authentication\Result as AuthenticationResult; use Zend\EventManager\EventManager; use Zend\EventManager\EventManagerAwareInterface; use Zend\EventManager\EventManagerInterface; -use Zend\Ldap\Exception\LdapException; use Zend\ServiceManager\ServiceManager; use Zend\ServiceManager\ServiceManagerAwareInterface; use ZfcUser\Authentication\Adapter\AbstractAdapter; @@ -41,6 +42,11 @@ class Ldap extends AbstractAdapter implements ServiceManagerAwareInterface, Even */ protected $ldapAuthAdapter; + /** + * @var LdapPeopleMapper + */ + protected $ldapPeopleMapper; + /** * @var ModuleOptions */ @@ -55,16 +61,21 @@ class Ldap extends AbstractAdapter implements ServiceManagerAwareInterface, Even * * @param AuthEvent $e * @return boolean - * @throws UnexpectedValueException + * @throws \Zend\Authentication\Adapter\Exception\ExceptionInterface + * @throws \Zend\Ldap\Exception\LdapException * @see ChainableAdapter */ public function authenticate(AuthEvent $e) { if ($this->isSatisfied()) { - $storage = $this->getStorage()->read(); + try { + $storage = $this->getStorage()->read(); + } catch (ExceptionInterface $e) { + throw new RuntimeException("Erreur de lecture du storage"); + } $e->setIdentity($storage['identity']) - ->setCode(AuthenticationResult::SUCCESS) - ->setMessages(['Authentication successful.']); + ->setCode(AuthenticationResult::SUCCESS) + ->setMessages(['Authentication successful.']); return; } @@ -82,28 +93,69 @@ class Ldap extends AbstractAdapter implements ServiceManagerAwareInterface, Even // Failure! if (! $success) { $e->setCode(AuthenticationResult::FAILURE) - ->setMessages(['LDAP bind failed.']); + ->setMessages(['LDAP bind failed.']); + $this->setSatisfied(false); + return false; + } + + // recherche de l'individu dans l'annuaire LDAP + $ldapPeople = $this->getLdapPeopleMapper()->findOneByUsername($username); + if (!$ldapPeople) { + $e + ->setCode(AuthenticationResult::FAILURE) + ->setMessages(['Authentication failed.']); $this->setSatisfied(false); return false; } $e->setIdentity($this->usernameUsurpe ?: $username); $this->setSatisfied(true); - $storage = $this->getStorage()->read(); - $storage['identity'] = $e->getIdentity(); - $this->getStorage()->write($storage); + try { + $storage = $this->getStorage()->read(); + $storage['identity'] = $e->getIdentity(); + $this->getStorage()->write($storage); + } catch (ExceptionInterface $e) { + throw new RuntimeException("Erreur de concernant le storage"); + } $e->setCode(AuthenticationResult::SUCCESS) - ->setMessages(['Authentication successful.']); + ->setMessages(['Authentication successful.']); + + /* @var $userService User */ + $userService = $this->getServiceManager()->get('unicaen-auth_user_service'); + $userService->userAuthenticated($ldapPeople); + } + + /** + * Extrait le loginUsurpateur et le loginUsurpé si l'identifiant spécifé est de la forme + * "loginUsurpateur=loginUsurpé". + * + * @param string $identifiant Identifiant, éventuellement de la forme "loginUsurpateur=loginUsurpé" + * @return array + * [loginUsurpateur, loginUsurpé] si l'identifiant est de la forme "loginUsurpateur=loginUsurpé" ; + * [] sinon. + */ + static public function extractUsernamesUsurpation($identifiant) + { + if (strpos($identifiant, self::USURPATION_USERNAMES_SEP) > 0) { + list($identifiant, $usernameUsurpe) = explode(self::USURPATION_USERNAMES_SEP, $identifiant, 2); + + return [ + $identifiant, + $usernameUsurpe + ]; + } - $this->getEventManager()->trigger('userAuthenticated', $e); + return []; } /** * Authentifie l'identifiant et le mot de passe spécifiés. * - * @param string $username Identifiant de connexion + * @param string $username Identifiant de connexion * @param string $credential Mot de passe * @return boolean + * @throws \Zend\Authentication\Adapter\Exception\ExceptionInterface + * @throws \Zend\Ldap\Exception\LdapException */ public function authenticateUsername($username, $credential) { @@ -111,20 +163,17 @@ class Ldap extends AbstractAdapter implements ServiceManagerAwareInterface, Even // - le format attendu est "loginUsurpateur=loginUsurpé" // - le mot de passe attendu est celui du compte usurpateur (loginUsurpateur) $this->usernameUsurpe = null; - if (strpos($username, self::USURPATION_USERNAMES_SEP) > 0) { - list($username, $this->usernameUsurpe) = explode(self::USURPATION_USERNAMES_SEP, $username, 2); + $usernames = self::extractUsernamesUsurpation($username); + if (count($usernames) === 2) { + list ($username, $this->usernameUsurpe) = $usernames; if (!in_array($username, $this->getOptions()->getUsurpationAllowedUsernames())) { $this->usernameUsurpe = null; } } // LDAP auth - - - /** @var Result $result */ $result = $this->getLdapAuthAdapter()->setUsername($username)->setPassword($credential)->authenticate(); - if ($result && count($result->getMessages())) { // Obtenir le message LDAP // $msg = preg_replace('/\[0x\d* \((.*)\):/','$1', $event->getParam('result')->getMessages()[1]); @@ -149,6 +198,31 @@ class Ldap extends AbstractAdapter implements ServiceManagerAwareInterface, Even return $success; } + /** + * get ldap people mapper + * + * @return LdapPeopleMapper + */ + public function getLdapPeopleMapper() + { + if (null === $this->ldapPeopleMapper) { + $this->ldapPeopleMapper = $this->getServiceManager()->get('ldap_people_mapper'); + } + return $this->ldapPeopleMapper; + } + + /** + * set ldap people mapper + * + * @param LdapPeopleMapper $mapper + * @return self + */ + public function setLdapPeopleMapper(LdapPeopleMapper $mapper) + { + $this->ldapPeopleMapper = $mapper; + return $this; + } + /** * @param ModuleOptions $options */ @@ -164,8 +238,8 @@ class Ldap extends AbstractAdapter implements ServiceManagerAwareInterface, Even { if (!$this->options instanceof ModuleOptions) { $options = array_merge( - $this->getServiceManager()->get('zfcuser_module_options')->toArray(), - $this->getServiceManager()->get('unicaen-auth_module_options')->toArray()); + $this->getServiceManager()->get('zfcuser_module_options')->toArray(), + $this->getServiceManager()->get('unicaen-auth_module_options')->toArray()); $this->setOptions(new ModuleOptions($options)); } return $this->options; @@ -250,6 +324,10 @@ class Ldap extends AbstractAdapter implements ServiceManagerAwareInterface, Even */ public function setEventManager(EventManagerInterface $eventManager) { + $eventManager->setIdentifiers([ + __NAMESPACE__, + __CLASS__, + ]); $this->eventManager = $eventManager; return $this; } diff --git a/src/UnicaenAuth/Authentication/Storage/ChainableStorage.php b/src/UnicaenAuth/Authentication/Storage/ChainableStorage.php index 8da41999f2756a3b1f5f8ea69f9c697c89366cdf..99f5f1b256da8effd52036e5a5fcacb7a508d568 100644 --- a/src/UnicaenAuth/Authentication/Storage/ChainableStorage.php +++ b/src/UnicaenAuth/Authentication/Storage/ChainableStorage.php @@ -2,8 +2,6 @@ namespace UnicaenAuth\Authentication\Storage; -use UnicaenAuth\Authentication\Storage\ChainEvent; - interface ChainableStorage { /** @@ -11,25 +9,21 @@ interface ChainableStorage * * Behavior is undefined when storage is empty. * - * @throws InvalidArgumentException If reading contents from storage is impossible - * @return People + * @param \UnicaenAuth\Authentication\Storage\ChainEvent $e */ public function read(ChainEvent $e); - + /** * Writes $contents to storage * - * @param mixed $contents - * @throws InvalidArgumentException If writing $contents to storage is impossible - * @return void + * @param \UnicaenAuth\Authentication\Storage\ChainEvent $e */ public function write(ChainEvent $e); /** * Clears contents from storage * - * @throws InvalidArgumentException If clearing contents from storage is impossible - * @return void + * @param \UnicaenAuth\Authentication\Storage\ChainEvent $e */ public function clear(ChainEvent $e); } \ No newline at end of file diff --git a/src/UnicaenAuth/Authentication/Storage/Shib.php b/src/UnicaenAuth/Authentication/Storage/Shib.php new file mode 100644 index 0000000000000000000000000000000000000000..1bc25efa09bfdb760746b6a8e63aa2ec2fad23d1 --- /dev/null +++ b/src/UnicaenAuth/Authentication/Storage/Shib.php @@ -0,0 +1,114 @@ +<?php + +namespace UnicaenAuth\Authentication\Storage; + +use UnicaenAuth\Entity\Shibboleth\ShibUser; +use UnicaenAuth\Options\ModuleOptions; +use UnicaenAuth\Service\ShibService; +use Zend\Authentication\Storage\Session; +use Zend\Authentication\Storage\StorageInterface; +use Zend\ServiceManager\ServiceLocatorAwareInterface; +use Zend\ServiceManager\ServiceLocatorAwareTrait; +use Zend\ServiceManager\ServiceManager; + +/** + * Shibboleth authentication storage. + * + * @author Unicaen + */ +class Shib implements ChainableStorage, ServiceLocatorAwareInterface +{ + use ServiceLocatorAwareTrait; + + /** + * @var StorageInterface + */ + protected $storage; + + /** + * @var ModuleOptions + */ + protected $options; + + /** + * @var ShibUser + */ + protected $resolvedIdentity; + + /** + * @var ServiceManager + */ + protected $serviceManager; + + /** + * Returns the contents of storage + * + * Behavior is undefined when storage is empty. + * + * @param ChainEvent $e + * @return ShibUser + * @throws \Zend\Authentication\Exception\ExceptionInterface + */ + public function read(ChainEvent $e) + { + /** @var ShibService $shib */ + $shib = $this->getServiceLocator()->get(ShibService::class); + $shibUser = $shib->getAuthenticatedUser(); + + $e->addContents('shib', $shibUser); + + return $shibUser; + } + + /** + * Writes $contents to storage + * + * @param ChainEvent $e + * @throws \Zend\Authentication\Exception\ExceptionInterface + */ + public function write(ChainEvent $e) + { + $contents = $e->getParam('contents'); + $this->resolvedIdentity = null; + $this->getStorage()->write($contents); + } + + /** + * Clears contents from storage + * + * @param ChainEvent $e + * @throws \Zend\Authentication\Exception\ExceptionInterface + */ + public function clear(ChainEvent $e) + { + $this->resolvedIdentity = null; + $this->getStorage()->clear(); + } + + /** + * getStorage + * + * @return StorageInterface + */ + public function getStorage() + { + if (null === $this->storage) { + $this->setStorage(new Session()); + } + + return $this->storage; + } + + /** + * setStorage + * + * @param StorageInterface $storage + * @return self + */ + public function setStorage(StorageInterface $storage) + { + $this->storage = $storage; + + return $this; + } +} diff --git a/src/UnicaenAuth/Controller/AuthController.php b/src/UnicaenAuth/Controller/AuthController.php new file mode 100644 index 0000000000000000000000000000000000000000..d3b468c39e9fc06686bdbd0a30023854a27e1124 --- /dev/null +++ b/src/UnicaenAuth/Controller/AuthController.php @@ -0,0 +1,73 @@ +<?php + +namespace UnicaenAuth\Controller; + +use UnicaenApp\Exception\RuntimeException; +use UnicaenAuth\Service\Traits\ShibServiceAwareTrait; +use UnicaenAuth\Service\Traits\UserServiceAwareTrait; +use Zend\Authentication\AuthenticationService; +use Zend\Authentication\Exception\ExceptionInterface; +use Zend\Http\Response; +use Zend\Mvc\Controller\AbstractActionController; +use ZfcUser\Controller\Plugin\ZfcUserAuthentication; + +/** + * Classe ajoutée lors de l'implémentation de l'auth Shibboleth. + * + * @method ZfcUserAuthentication zfcUserAuthentication() + * @author Bertrand GAUTHIER <bertrand.gauthier at unicaen.fr> + */ +class AuthController extends AbstractActionController +{ + use ShibServiceAwareTrait; + use UserServiceAwareTrait; + + /** + * @return Response|array + */ + public function shibbolethAction() + { + $operation = $this->params()->fromRoute('operation'); + + if ($operation === 'deconnexion') { + // déconnexion applicative quoiqu'il arrive + $this->zfcUserAuthentication()->getAuthAdapter()->resetAdapters(); + $this->zfcUserAuthentication()->getAuthAdapter()->logoutAdapters(); + $this->zfcUserAuthentication()->getAuthService()->clearIdentity(); + + // déconnexion Shibboleth le cas échéant + if ($this->shibService->isShibbolethEnable()) { + $homeUrl = $this->url()->fromRoute('home', [], ['force_canonical' => true]); + $returnAbsoluteUrl = $this->params()->fromQuery('return', $homeUrl); + return $this->redirect()->toUrl($this->shibService->getLogoutUrl($returnAbsoluteUrl)); + } else { + return []; // une page d'aide s'affichera + } + } + + $shibUser = $this->shibService->getAuthenticatedUser(); + + if ($shibUser === null) { + return []; // une page d'aide s'affichera + } + + /** @var AuthenticationService $authService */ + $authService = $this->getServiceLocator()->get('zfcuser_auth_service'); + try { + $authService->getStorage()->write($shibUser->getId()); + } catch (ExceptionInterface $e) { + throw new RuntimeException("Impossible d'écrire dans le storage"); + } + + $this->userService->userAuthenticated($shibUser); + + $redirectUrl = $this->params()->fromQuery('redirect', '/'); + + return $this->redirect()->toUrl($redirectUrl); + } + + public function shibboleth() + { + + } +} \ No newline at end of file diff --git a/src/UnicaenAuth/Controller/AuthControllerFactory.php b/src/UnicaenAuth/Controller/AuthControllerFactory.php new file mode 100644 index 0000000000000000000000000000000000000000..e771651f537a0b3566d3de03b8fbc24ecce55068 --- /dev/null +++ b/src/UnicaenAuth/Controller/AuthControllerFactory.php @@ -0,0 +1,29 @@ +<?php + +namespace UnicaenAuth\Controller; + +use UnicaenAuth\Service\ShibService; +use UnicaenAuth\Service\User as UserService; +use Zend\Mvc\Controller\ControllerManager; + +class AuthControllerFactory +{ + /** + * @param ControllerManager $cm + * @return AuthController + */ + public function __invoke(ControllerManager $cm) + { + /** @var ShibService $shibService */ + $shibService = $cm->getServiceLocator()->get(ShibService::class); + + /* @var $userService UserService */ + $userService = $cm->getServiceLocator()->get('unicaen-auth_user_service'); + + $controller = new AuthController(); + $controller->setShibService($shibService); + $controller->setUserService($userService); + + return $controller; + } +} \ No newline at end of file diff --git a/src/UnicaenAuth/Controller/DroitsController.php b/src/UnicaenAuth/Controller/DroitsController.php index cb0343fce9b4854f0a9096ae1dea4cda1dd725ff..a4970f0b469bb760322a2d699183bbdae6d966d9 100644 --- a/src/UnicaenAuth/Controller/DroitsController.php +++ b/src/UnicaenAuth/Controller/DroitsController.php @@ -2,8 +2,6 @@ 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; @@ -11,11 +9,9 @@ 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 @@ -24,19 +20,11 @@ class DroitsController extends AbstractActionController use RoleFormAwareTrait; use PrivilegeServiceAwareTrait; - - - /** - * - * @return type - */ public function indexAction() { return []; } - - public function rolesAction() { $roles = $this->getServiceRole()->getList(); @@ -44,8 +32,6 @@ class DroitsController extends AbstractActionController return compact('roles'); } - - public function roleEditionAction() { $roleId = $this->params()->fromRoute('role'); @@ -79,8 +65,6 @@ class DroitsController extends AbstractActionController return compact('form', 'title', 'errors'); } - - public function roleSuppressionAction() { $roleId = $this->params()->fromRoute('role'); @@ -101,8 +85,6 @@ class DroitsController extends AbstractActionController return compact('role', 'title', 'form', 'errors'); } - - public function privilegesAction() { $ps = $this->getServicePrivilege()->getList(); @@ -123,8 +105,6 @@ class DroitsController extends AbstractActionController return compact('privileges', 'roles'); } - - public function privilegesModifierAction() { $roleId = $this->params()->fromPost('role'); @@ -151,8 +131,6 @@ class DroitsController extends AbstractActionController return $viewModel; } - - public function getFormSupprimer() { $form = new Form(); diff --git a/src/UnicaenAuth/Entity/Db/AbstractPrivilege.php b/src/UnicaenAuth/Entity/Db/AbstractPrivilege.php new file mode 100644 index 0000000000000000000000000000000000000000..2883ac8459ac8020a407a81d82e57742f418c03e --- /dev/null +++ b/src/UnicaenAuth/Entity/Db/AbstractPrivilege.php @@ -0,0 +1,227 @@ +<?php + +namespace UnicaenAuth\Entity\Db; + +use Doctrine\Common\Collections\Collection; +use UnicaenAuth\Provider\Privilege\Privileges; +use Zend\Permissions\Acl\Resource\ResourceInterface; +use Doctrine\ORM\Mapping as ORM; + +/** + * Privilege entity abstract mother class. + * + * @ORM\MappedSuperclass + */ +abstract class AbstractPrivilege implements PrivilegeInterface, ResourceInterface +{ + /** + * @var int + * @ORM\Id + * @ORM\Column(type="integer") + * @ORM\GeneratedValue(strategy="AUTO") + */ + protected $id; + + /** + * @var string + * @ORM\Column(name="code", type="string", length=150, unique=false, nullable=false) + */ + protected $code; + + /** + * @var string + * @ORM\Column(name="libelle", type="string", length=200, unique=false, nullable=false) + */ + protected $libelle; + + /** + * @var int + * @ORM\Column(name="ordre", type="integer", unique=false, nullable=true) + */ + protected $ordre; + + /** + * @var CategoriePrivilege + * @ORM\ManyToOne(targetEntity="CategoriePrivilege", inversedBy="privilege") + * @ORM\JoinColumn(name="categorie_id", referencedColumnName="id") + */ + protected $categorie; + + /** + * @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")} + * + * ) + */ + protected $role; + + /** + * Constructor + */ + public function __construct() + { + $this->role = 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; + } + + public function getFullCode() + { + return $this->getCategorie()->getCode() . '-' . $this->getCode(); + } + + /** + * 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 self + */ + function setOrdre($ordre) + { + $this->ordre = $ordre; + + return $this; + } + + /** + * Get id + * + * @return integer + */ + public function getId() + { + return $this->id; + } + + /** + * Set categorie + * + * @param CategoriePrivilege $categorie + * + * @return self + */ + public function setCategorie(CategoriePrivilege $categorie = null) + { + $this->categorie = $categorie; + + return $this; + } + + /** + * Get categorie + * + * @return CategoriePrivilege + */ + public function getCategorie() + { + return $this->categorie; + } + + /** + * Add role + * + * @param RoleInterface $role + * + * @return self + */ + public function addRole(RoleInterface $role) + { + $this->role->add($role); + + return $this; + } + + /** + * Remove role + * + * @param RoleInterface $role + */ + public function removeRole(RoleInterface $role) + { + $this->role->removeElement($role); + } + + /** + * Get role + * + * @return Collection + */ + public function getRole() + { + return $this->role; + } + + /** + * @return string + */ + public function __toString() + { + return $this->getLibelle(); + } + + /** + * @return string + */ + public function getResourceId() + { + return Privileges::getResourceId($this); + } +} \ No newline at end of file diff --git a/src/UnicaenAuth/Entity/Db/AbstractRole.php b/src/UnicaenAuth/Entity/Db/AbstractRole.php new file mode 100644 index 0000000000000000000000000000000000000000..aaa2e6cb05f9ca59c221ecd7cde903bda9e34250 --- /dev/null +++ b/src/UnicaenAuth/Entity/Db/AbstractRole.php @@ -0,0 +1,202 @@ +<?php + +namespace UnicaenAuth\Entity\Db; + +use Doctrine\ORM\Mapping as ORM; + +/** + * Role entity abstract mother class. + * + * @ORM\MappedSuperclass + */ +abstract class AbstractRole implements RoleInterface +{ + /** + * @var int + * @ORM\Id + * @ORM\Column(type="integer") + * @ORM\GeneratedValue(strategy="AUTO") + */ + protected $id; + + /** + * @var string + * @ORM\Column(name="role_id", type="string", length=255, unique=true, nullable=false) + */ + protected $roleId; + + /** + * @var boolean + * @ORM\Column(name="is_default", type="boolean", nullable=true) + */ + protected $isDefault = false; + + /** + * @var Role + * @ORM\ManyToOne(targetEntity="Role") + */ + protected $parent; + + /** + * @var string + * @ORM\Column(name="ldap_filter", type="string", length=255, unique=true, nullable=true) + */ + protected $ldapFilter; + + /** + * @var \Doctrine\Common\Collections\Collection + * @ORM\ManyToMany(targetEntity="UnicaenAuth\Entity\Db\User") + * @ORM\JoinTable(name="user_role_linker", + * joinColumns={@ORM\JoinColumn(name="user_id", referencedColumnName="id")}, + * inverseJoinColumns={@ORM\JoinColumn(name="role_id", referencedColumnName="id")} + * ) + */ + protected $users; + + /** + * Get the id. + * + * @return int + */ + public function getId() + { + return $this->id; + } + + /** + * Set the id. + * + * @param int $id + * + * @return self + */ + public function setId($id) + { + $this->id = (int)$id; + + return $this; + } + + /** + * Get the role id. + * + * @return string + */ + public function getRoleId() + { + return $this->roleId; + } + + /** + * Set the role id. + * + * @param string $roleId + * + * @return self + */ + public function setRoleId($roleId) + { + $this->roleId = (string)$roleId; + + return $this; + } + + /** + * Is this role the default one ? + * + * @return boolean + */ + public function getIsDefault() + { + return $this->isDefault; + } + + /** + * Set this role as the default one. + * + * @param boolean $isDefault + * + * @return self + */ + public function setIsDefault($isDefault) + { + $this->isDefault = (boolean)$isDefault; + + return $this; + } + + /** + * Get the parent role + * + * @return Role + */ + public function getParent() + { + return $this->parent; + } + + /** + * Set the parent role. + * + * @param RoleInterface $parent + * + * @return self + */ + public function setParent(RoleInterface $parent = null) + { + $this->parent = $parent; + + return $this; + } + + /** + * @return string + */ + public function getLdapFilter() + { + return $this->ldapFilter; + } + + /** + * @param string $ldapFilter + * + * @return Role + */ + public function setLdapFilter($ldapFilter) + { + $this->ldapFilter = $ldapFilter; + + return $this; + } + + /** + * Get users. + * + * @return array + */ + public function getUsers() + { + return $this->users->getValues(); + } + + /** + * Add a user to the role. + * + * @param UserInterface $user + * + * @return void + */ + public function addUser(UserInterface $user) + { + $this->users[] = $user; + } + + /** + * + * @return string + */ + public function __toString() + { + return $this->getRoleId(); + } +} \ No newline at end of file diff --git a/src/UnicaenAuth/Entity/Db/AbstractUser.php b/src/UnicaenAuth/Entity/Db/AbstractUser.php index 654891a03a91bc7a11130ca922018eda8fa546a1..e19aba664c5006252e0ad54fd581e13bf2ef83a0 100644 --- a/src/UnicaenAuth/Entity/Db/AbstractUser.php +++ b/src/UnicaenAuth/Entity/Db/AbstractUser.php @@ -1,12 +1,11 @@ <?php - + namespace UnicaenAuth\Entity\Db; use BjyAuthorize\Provider\Role\ProviderInterface; use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\Collection; use Doctrine\ORM\Mapping as ORM; -use ZfcUser\Entity\UserInterface; /** * User entity abstract mother class. @@ -216,17 +215,17 @@ abstract class AbstractUser implements UserInterface, ProviderInterface /** * Add a role to the user. * - * @param Role $role + * @param RoleInterface $role * * @return void */ - public function addRole(Role $role) + public function addRole(RoleInterface $role) { $this->roles->add($role); } - + /** - * + * * @return string */ public function __toString() diff --git a/src/UnicaenAuth/Entity/Db/CategoriePrivilege.php b/src/UnicaenAuth/Entity/Db/CategoriePrivilege.php index e3009d9e13bebb094a1659c44171ae78fcccadc8..6f91c1adc06a65d1736d1c39b8e6323229d85da9 100644 --- a/src/UnicaenAuth/Entity/Db/CategoriePrivilege.php +++ b/src/UnicaenAuth/Entity/Db/CategoriePrivilege.php @@ -2,6 +2,7 @@ namespace UnicaenAuth\Entity\Db; +use Doctrine\Common\Collections\ArrayCollection; use Doctrine\ORM\Mapping as ORM; /** @@ -43,18 +44,14 @@ class CategoriePrivilege */ private $privilege; - - /** * Constructor */ public function __construct() { - $this->privilege = new \Doctrine\Common\Collections\ArrayCollection(); + $this->privilege = new ArrayCollection(); } - - /** * Set code * @@ -69,8 +66,6 @@ class CategoriePrivilege return $this; } - - /** * Get code * @@ -81,8 +76,6 @@ class CategoriePrivilege return $this->code; } - - /** * Set libelle * @@ -97,8 +90,6 @@ class CategoriePrivilege return $this; } - - /** * Get libelle * @@ -109,8 +100,6 @@ class CategoriePrivilege return $this->libelle; } - - /** * * @return integer @@ -120,8 +109,6 @@ class CategoriePrivilege return $this->ordre; } - - /** * * @param integer $ordre @@ -135,8 +122,6 @@ class CategoriePrivilege return $this; } - - /** * Get id * @@ -147,8 +132,6 @@ class CategoriePrivilege return $this->id; } - - /** * Add privilege * @@ -163,8 +146,6 @@ class CategoriePrivilege return $this; } - - /** * Remove privilege * @@ -175,8 +156,6 @@ class CategoriePrivilege $this->privilege->removeElement($privilege); } - - /** * Get privilege * @@ -187,8 +166,6 @@ class CategoriePrivilege return $this->privilege; } - - /** * @return string */ @@ -196,4 +173,4 @@ class CategoriePrivilege { return $this->getLibelle(); } -} +} \ No newline at end of file diff --git a/src/UnicaenAuth/Entity/Db/Privilege.php b/src/UnicaenAuth/Entity/Db/Privilege.php index 4e0b7ae858eeea4023d55e1dd4cd53a9bf1ac29e..77702cd0dbaf1fface8c7530a1a068c076146ea8 100644 --- a/src/UnicaenAuth/Entity/Db/Privilege.php +++ b/src/UnicaenAuth/Entity/Db/Privilege.php @@ -2,257 +2,15 @@ namespace UnicaenAuth\Entity\Db; -use UnicaenAuth\Provider\Privilege\Privileges; -use Zend\Permissions\Acl\Resource\ResourceInterface; use Doctrine\ORM\Mapping as ORM; /** + * Privilege entity class. * * @ORM\Entity * @ORM\Table(name="privilege") */ -class Privilege implements ResourceInterface +class Privilege extends AbstractPrivilege { - /** - * @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=true) - */ - private $ordre; - - /** - * @var CategoriePrivilege - * @ORM\ManyToOne(targetEntity="CategoriePrivilege", inversedBy="privilege") - * @ORM\JoinColumn(name="categorie_id", referencedColumnName="id") - */ - private $categorie; - - /** - * @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; - - - - /** - * Constructor - */ - public function __construct() - { - $this->role = 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; - } - - - - public function getFullCode() - { - return $this->getCategorie()->getCode() . '-' . $this->getCode(); - } - - - - /** - * 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 self - */ - function setOrdre($ordre) - { - $this->ordre = $ordre; - - return $this; - } - - - - /** - * Get id - * - * @return integer - */ - public function getId() - { - return $this->id; - } - - - - /** - * Set categorie - * - * @param CategoriePrivilege $categorie - * - * @return self - */ - public function setCategorie(CategoriePrivilege $categorie = null) - { - $this->categorie = $categorie; - - return $this; - } - - - - /** - * Get categorie - * - * @return CategoriePrivilege - */ - public function getCategorie() - { - return $this->categorie; - } - - - - /** - * Add role - * - * @param Role $role - * - * @return self - */ - public function addRole(Role $role) - { - $this->role->add($role); - - return $this; - } - - - - /** - * Remove role - * - * @param Role $role - */ - public function removeRole(Role $role) - { - $this->role->removeElement($role); - } - - - - /** - * Get role - * - * @return \Doctrine\Common\Collections\Collection - */ - public function getRole() - { - return $this->role; - } - - - - /** - * @return string - */ - public function __toString() - { - return $this->getLibelle(); - } - - - - /** - * @return string - */ - public function getResourceId() - { - return Privileges::getResourceId($this); - } } diff --git a/src/UnicaenAuth/Entity/Db/PrivilegeInterface.php b/src/UnicaenAuth/Entity/Db/PrivilegeInterface.php new file mode 100644 index 0000000000000000000000000000000000000000..e8f7469debc41dd751ff14f857589046b1458e59 --- /dev/null +++ b/src/UnicaenAuth/Entity/Db/PrivilegeInterface.php @@ -0,0 +1,83 @@ +<?php + +namespace UnicaenAuth\Entity\Db; + +use Doctrine\Common\Collections\Collection; + +interface PrivilegeInterface +{ + /** + * @param string $code + * @return self + */ + public function setCode($code); + + /** + * @return string + */ + public function getCode(); + + /** + * @return string + */ + public function getFullCode(); + + /** + * @param string $libelle + * @return self + */ + public function setLibelle($libelle); + + /** + * @return string + */ + public function getLibelle(); + + /** + * @return integer + */ + function getOrdre(); + + /** + * @param integer $ordre + * @return self + */ + function setOrdre($ordre); + + /** + * @return integer + */ + public function getId(); + + /** + * @param CategoriePrivilege $categorie + * @return self + */ + public function setCategorie(CategoriePrivilege $categorie = null); + + /** + * @return CategoriePrivilege + */ + public function getCategorie(); + + /** + * @param RoleInterface $role + * @return self + */ + public function addRole(RoleInterface $role); + + /** + * @param RoleInterface $role + */ + public function removeRole(RoleInterface $role); + + /** + * @return Collection + */ + public function getRole(); + + /** + * @return string + */ + public function __toString(); +} \ No newline at end of file diff --git a/src/UnicaenAuth/Entity/Db/Role.php b/src/UnicaenAuth/Entity/Db/Role.php index fe8a4c7a04713dcce5b23fb7f044d0c17750a45c..70ff84981354ed0aeee9fddad1897701e11b90b6 100644 --- a/src/UnicaenAuth/Entity/Db/Role.php +++ b/src/UnicaenAuth/Entity/Db/Role.php @@ -1,236 +1,16 @@ <?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\Entity\Db; -use BjyAuthorize\Acl\HierarchicalRoleInterface; use Doctrine\ORM\Mapping as ORM; /** - * An example entity that represents a role. + * Role entity class. * * @ORM\Entity * @ORM\Table(name="user_role") */ -class Role implements HierarchicalRoleInterface +class Role extends AbstractRole { - /** - * @var int - * @ORM\Id - * @ORM\Column(type="integer") - * @ORM\GeneratedValue(strategy="AUTO") - */ - protected $id; - - /** - * @var string - * @ORM\Column(name="role_id", type="string", length=255, unique=true, nullable=false) - */ - protected $roleId; - - /** - * @var boolean - * @ORM\Column(name="is_default", type="boolean", nullable=true) - */ - protected $isDefault = false; - - /** - * @var Role - * @ORM\ManyToOne(targetEntity="Role") - */ - protected $parent; - - /** - * @var string - * @ORM\Column(name="ldap_filter", type="string", length=255, unique=true, nullable=true) - */ - protected $ldapFilter; - - /** - * @var \Doctrine\Common\Collections\Collection - * @ORM\ManyToMany(targetEntity="UnicaenAuth\Entity\Db\User") - * @ORM\JoinTable(name="user_role_linker", - * joinColumns={@ORM\JoinColumn(name="user_id", referencedColumnName="id")}, - * inverseJoinColumns={@ORM\JoinColumn(name="role_id", referencedColumnName="id")} - * ) - */ - protected $users; - - - - /** - * Get the id. - * - * @return int - */ - public function getId() - { - return $this->id; - } - - - - /** - * Set the id. - * - * @param int $id - * - * @return self - */ - public function setId($id) - { - $this->id = (int)$id; - - return $this; - } - - - - /** - * Get the role id. - * - * @return string - */ - public function getRoleId() - { - return $this->roleId; - } - - - - /** - * Set the role id. - * - * @param string $roleId - * - * @return self - */ - public function setRoleId($roleId) - { - $this->roleId = (string)$roleId; - - return $this; - } - - - - /** - * Is this role the default one ? - * - * @return boolean - */ - public function getIsDefault() - { - return $this->isDefault; - } - - - - /** - * Set this role as the default one. - * - * @param boolean $isDefault - * - * @return self - */ - public function setIsDefault($isDefault) - { - $this->isDefault = (boolean)$isDefault; - - return $this; - } - - - - /** - * Get the parent role - * - * @return Role - */ - public function getParent() - { - return $this->parent; - } - - - - /** - * Set the parent role. - * - * @param Role $role - * - * @return self - */ - public function setParent(Role $parent = null) - { - $this->parent = $parent; - - return $this; - } - - - - /** - * @return string - */ - public function getLdapFilter() - { - return $this->ldapFilter; - } - - - - /** - * @param string $ldapFilter - * - * @return Role - */ - public function setLdapFilter($ldapFilter) - { - $this->ldapFilter = $ldapFilter; - - return $this; - } - - - - /** - * Get users. - * - * @return array - */ - public function getUsers() - { - return $this->users->getValues(); - } - - - - /** - * Add a user to the role. - * - * @param User $user - * - * @return void - */ - public function addUser($user) - { - $this->users[] = $user; - } - - - /** - * - * @return string - */ - public function __toString() - { - return $this->getRoleId(); - } } \ No newline at end of file diff --git a/src/UnicaenAuth/Entity/Db/RoleInterface.php b/src/UnicaenAuth/Entity/Db/RoleInterface.php new file mode 100644 index 0000000000000000000000000000000000000000..1555fa4c604f264b2ce0105d9b4a9bf2d4c80b55 --- /dev/null +++ b/src/UnicaenAuth/Entity/Db/RoleInterface.php @@ -0,0 +1,79 @@ +<?php + +namespace UnicaenAuth\Entity\Db; + +use BjyAuthorize\Acl\HierarchicalRoleInterface; + +interface RoleInterface extends HierarchicalRoleInterface +{ + /** + * @param int $id + * @return self + */ + public function setId($id); + + /** + * @return int + */ + public function getId(); + + /** + * @return string + */ + public function getRoleId(); + + /** + * @param string $roleId + * @return self + */ + public function setRoleId($roleId); + + /** + * @return boolean + */ + public function getIsDefault(); + + /** + * @param boolean $isDefault + * @return self + */ + public function setIsDefault($isDefault); + + /** + * @return RoleInterface|null + */ + public function getParent(); + + /** + * @param RoleInterface|null $parent + * @return self + */ + public function setParent(RoleInterface $parent = null); + + /** + * @return string + */ + public function getLdapFilter(); + + /** + * @param string $ldapFilter + * @return self + */ + public function setLdapFilter($ldapFilter); + + /** + * @return UserInterface[] + */ + public function getUsers(); + + /** + * @param UserInterface $user + * @return self + */ + public function addUser(UserInterface $user); + + /** + * @return string + */ + public function __toString(); +} \ No newline at end of file diff --git a/src/UnicaenAuth/Entity/Db/User.php b/src/UnicaenAuth/Entity/Db/User.php index b041a31a6a4b04f63dac57fb1a0329cf6ceb3a36..77209f677574bfb1a1b7aa0e232b4aa2d9daaf73 100644 --- a/src/UnicaenAuth/Entity/Db/User.php +++ b/src/UnicaenAuth/Entity/Db/User.php @@ -1,5 +1,5 @@ <?php - + namespace UnicaenAuth\Entity\Db; use Doctrine\ORM\Mapping as ORM; @@ -12,5 +12,5 @@ use Doctrine\ORM\Mapping as ORM; */ class User extends AbstractUser { - + } \ No newline at end of file diff --git a/src/UnicaenAuth/Entity/Db/UserInterface.php b/src/UnicaenAuth/Entity/Db/UserInterface.php new file mode 100644 index 0000000000000000000000000000000000000000..479a859259d8df604542c0bf700e3f490c66045e --- /dev/null +++ b/src/UnicaenAuth/Entity/Db/UserInterface.php @@ -0,0 +1,92 @@ +<?php + +namespace UnicaenAuth\Entity\Db; + +use Doctrine\Common\Collections\Collection; + +interface UserInterface extends \ZfcUser\Entity\UserInterface +{ + /** + * @return int + */ + public function getId(); + + /** + * @param int $id + * @return self + */ + public function setId($id); + + /** + * @return string + */ + public function getUsername(); + + /** + * @param string $username + * @return self + */ + public function setUsername($username); + + /** + * @return string + */ + public function getEmail(); + + /** + * @param string $email + * @return self + */ + public function setEmail($email); + + /** + * @return string + */ + public function getDisplayName(); + + /** + * @param string $displayName + * @return self + */ + public function setDisplayName($displayName); + + /** + * Get password. + * + * @return string + */ + public function getPassword(); + + /** + * @param string $password + * @return self + */ + public function setPassword($password); + + /** + * @return int + */ + public function getState(); + + /** + * @param int $state + * @return self + */ + public function setState($state); + + /** + * @return Collection + */ + public function getRoles(); + + /** + * @param RoleInterface $role + * @return self + */ + public function addRole(RoleInterface $role); + + /** + * @return string + */ + public function __toString(); +} \ No newline at end of file diff --git a/src/UnicaenAuth/Entity/Shibboleth/ShibUser.php b/src/UnicaenAuth/Entity/Shibboleth/ShibUser.php new file mode 100644 index 0000000000000000000000000000000000000000..a51faa91f492fce9ed8260fa48bb533f4f2af6ef --- /dev/null +++ b/src/UnicaenAuth/Entity/Shibboleth/ShibUser.php @@ -0,0 +1,171 @@ +<?php + +namespace UnicaenAuth\Entity\Shibboleth; + +use ZfcUser\Entity\UserInterface; + +class ShibUser implements UserInterface +{ + /** + * @var string + */ + protected $id; + + /** + * @var string + */ + protected $username; + + /** + * @var string + */ + protected $email; + + /** + * @var string + */ + protected $displayName; + + /** + * @var int + */ + protected $state = 1; + + + /** + * @return string + */ + public function getEppn() + { + return $this->getUsername(); + } + + /** + * Get id. + * + * @return string + */ + public function getId() + { + return $this->id; + } + + /** + * Set id. + * + * @param string $id + */ + public function setId($id) + { + $this->id = $id; + } + + /** + * Get username. + * + * @return string + */ + public function getUsername() + { + return $this->username; + } + + /** + * Set username. + * + * @param string $username + */ + public function setUsername($username) + { + $this->username = $username; + } + + /** + * Get email. + * + * @return string + */ + public function getEmail() + { + return $this->email; + } + + /** + * Set email. + * + * @param string $email + */ + public function setEmail($email) + { + $this->email = $email; + } + + /** + * Get displayName. + * + * @return string + */ + public function getDisplayName() + { + return $this->displayName; + } + + /** + * Set displayName. + * + * @param string $displayName + */ + public function setDisplayName($displayName) + { + $this->displayName = $displayName; + } + + /** + * Get password. + * + * @return string + */ + public function getPassword() + { + return 'shib'; + } + + /** + * Set password. + * + * @param string $password + */ + public function setPassword($password) + { + + } + + /** + * Get state. + * + * @return int + */ + public function getState() + { + return $this->state; + } + + /** + * Set state. + * + * @param int $state + */ + public function setState($state) + { + $this->state = $state; + } + + /** + * + * @return string + */ + public function __toString() + { + return $this->getDisplayName(); + } +} \ No newline at end of file diff --git a/src/UnicaenAuth/Event/Listener/UserRoleSelectedEventAbstractListener.php b/src/UnicaenAuth/Event/Listener/UserRoleSelectedEventAbstractListener.php index 9d56da029d3113e7c66d10d760071f1bc9ab2b3c..24410c2b111b2719c2b588197d6437920b1c4e99 100644 --- a/src/UnicaenAuth/Event/Listener/UserRoleSelectedEventAbstractListener.php +++ b/src/UnicaenAuth/Event/Listener/UserRoleSelectedEventAbstractListener.php @@ -28,7 +28,6 @@ abstract class UserRoleSelectedEventAbstractListener implements ListenerAggregat * Renseigne les relations 'intervenant' et 'personnel' avant que l'objet soit persisté. * * @param UserRoleSelectedEvent $e - * @return */ abstract public function postSelection(UserRoleSelectedEvent $e); diff --git a/src/UnicaenAuth/Event/UserAuthenticatedEvent.php b/src/UnicaenAuth/Event/UserAuthenticatedEvent.php index dfb893f354844b479b602efedaf14f51b80f32da..725bf30aa88ccdf8a86b74852c71d7eaa5ad637a 100644 --- a/src/UnicaenAuth/Event/UserAuthenticatedEvent.php +++ b/src/UnicaenAuth/Event/UserAuthenticatedEvent.php @@ -2,6 +2,7 @@ namespace UnicaenAuth\Event; +use UnicaenAuth\Entity\Shibboleth\ShibUser; use UnicaenApp\Entity\Ldap\People; use Zend\EventManager\Event; use ZfcUser\Entity\UserInterface; @@ -14,12 +15,26 @@ use ZfcUser\Entity\UserInterface; class UserAuthenticatedEvent extends Event { const PRE_PERSIST = 'prePersist'; + const PARAM_DB_USER = 'db_user'; const PARAM_LDAP_USER = 'ldap_user'; - + const PARAM_SHIB_USER = 'shib_user'; + + /** + * Spécifie l'entité utilisateur issue de la base de données. + * + * @param UserInterface $dbUser + * @return UserAuthenticatedEvent + */ + public function setDbUser(UserInterface $dbUser) + { + $this->setParam(self::PARAM_DB_USER, $dbUser); + return $this; + } + /** * Retourne l'entité utilisateur issue de la base de données. - * + * * @return UserInterface */ public function getDbUser() @@ -27,9 +42,21 @@ class UserAuthenticatedEvent extends Event return $this->getParam(self::PARAM_DB_USER); } + /** + * Spécifie l'entité utilisateur issue de l'annuaire LDAP. + * + * @param People $ldapUser + * @return UserAuthenticatedEvent + */ + public function setLdapUser(People $ldapUser) + { + $this->setParam(self::PARAM_LDAP_USER, $ldapUser); + return $this; + } + /** * Retourne l'entité utilisateur issue de l'annuaire LDAP. - * + * * @return People */ public function getLdapUser() @@ -38,26 +65,24 @@ class UserAuthenticatedEvent extends Event } /** - * Spécifie l'entité utilisateur issue de la base de données. - * - * @param UserInterface $dbUser + * Spécifie l'entité utilisateur issue de l'authentification Shibboleth. + * + * @param ShibUser $shibUser * @return UserAuthenticatedEvent */ - public function setDbUser(UserInterface $dbUser) + public function setShibUser(ShibUser $shibUser) { - $this->setParam(self::PARAM_DB_USER, $dbUser); + $this->setParam(self::PARAM_SHIB_USER, $shibUser); return $this; } /** - * Spécifie l'entité utilisateur issue de l'annuaire LDAP. - * - * @param People $ldapUser - * @return UserAuthenticatedEvent + * Retourne l'entité utilisateur issue de l'authentification Shibboleth. + * + * @return ShibUser */ - public function setLdapUser(People $ldapUser) + public function getShibUser() { - $this->setParam(self::PARAM_LDAP_USER, $ldapUser); - return $this; + return $this->getParam(self::PARAM_SHIB_USER); } } \ No newline at end of file diff --git a/src/UnicaenAuth/Options/ModuleOptions.php b/src/UnicaenAuth/Options/ModuleOptions.php index c5f942aa1972f0a539647a42adcfdda7fac5d7d3..4d3b5fb5570b353bda22c0e452f6d71517ed6cc1 100644 --- a/src/UnicaenAuth/Options/ModuleOptions.php +++ b/src/UnicaenAuth/Options/ModuleOptions.php @@ -1,4 +1,5 @@ <?php + namespace UnicaenAuth\Options; /** @@ -18,6 +19,11 @@ class ModuleOptions extends \ZfcUser\Options\ModuleOptions */ protected $saveLdapUserInDatabase = false; + /** + * @var array + */ + protected $shibboleth = []; + /** * @var array */ @@ -27,9 +33,7 @@ class ModuleOptions extends \ZfcUser\Options\ModuleOptions * @var string */ protected $entityManagerName = 'doctrine.entitymanager.orm_default'; - - - + /** * set usernames allowed to make usurpation * @@ -44,8 +48,6 @@ class ModuleOptions extends \ZfcUser\Options\ModuleOptions return $this; } - - /** * get usernames allowed to make usurpation * @@ -56,8 +58,6 @@ 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 @@ -72,9 +72,7 @@ class ModuleOptions extends \ZfcUser\Options\ModuleOptions 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 @@ -85,9 +83,7 @@ class ModuleOptions extends \ZfcUser\Options\ModuleOptions { return $this->saveLdapUserInDatabase; } - - - + /** * set cas connection params * @@ -101,9 +97,7 @@ class ModuleOptions extends \ZfcUser\Options\ModuleOptions return $this; } - - - + /** * get cas connection params * @@ -113,9 +107,31 @@ class ModuleOptions extends \ZfcUser\Options\ModuleOptions { return $this->cas; } + + /** + * set shibboleth connection params + * + * @param array $shibboleth + * + * @return ModuleOptions + */ + public function setShibboleth(array $shibboleth = []) + { + $this->shibboleth = $shibboleth; + return $this; + } - + /** + * get shibboleth connection params + * + * @return array + */ + public function getShibboleth() + { + return $this->shibboleth; + } + /** * @return string */ @@ -123,9 +139,7 @@ class ModuleOptions extends \ZfcUser\Options\ModuleOptions { return $this->entityManagerName; } - - - + /** * @param string $entityManagerName * @@ -137,6 +151,4 @@ class ModuleOptions extends \ZfcUser\Options\ModuleOptions return $this; } - - } \ No newline at end of file diff --git a/src/UnicaenAuth/Provider/Identity/Db.php b/src/UnicaenAuth/Provider/Identity/Db.php index baa3f1453eb21b3538bc4169011a0e09bf91de18..cb92485e2cb12198ee7120d4922cdffc7959e54b 100644 --- a/src/UnicaenAuth/Provider/Identity/Db.php +++ b/src/UnicaenAuth/Provider/Identity/Db.php @@ -4,10 +4,9 @@ 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\Entity\Db\AbstractRole; use UnicaenAuth\Service\Traits\RoleServiceAwareTrait; use Zend\Ldap\Ldap; -use Zend\ServiceManager\ServiceLocatorAwareTrait; use ZfcUser\Entity\UserInterface; use Traversable; @@ -91,12 +90,12 @@ class Db extends AuthenticationIdentityProvider implements ChainableProvider, \B /** - * @param Role $role + * @param AbstractRole $role * @param string $dn * * @return bool */ - protected function roleMatches(Role $role, $dn) + protected function roleMatches(AbstractRole $role, $dn) { try { return 1 === $this->getLdap()->count($role->getLdapFilter(), $dn, Ldap::SEARCH_SCOPE_SUB); diff --git a/src/UnicaenAuth/Service/AbstractService.php b/src/UnicaenAuth/Service/AbstractService.php index 190b8cbd8d3a7e75fdd1e2553ed3d8ae11680638..6ed1d710e51eb6887be836c9a49142a244a7216e 100644 --- a/src/UnicaenAuth/Service/AbstractService.php +++ b/src/UnicaenAuth/Service/AbstractService.php @@ -17,8 +17,6 @@ abstract class AbstractService implements ServiceLocatorAwareInterface */ private $serviceAuthorize; - - /** * @return \UnicaenAuth\Service\AuthorizeService */ @@ -31,12 +29,10 @@ abstract class AbstractService implements ServiceLocatorAwareInterface return $this->serviceAuthorize; } - - /** * @return \Doctrine\ORM\EntityManager */ - protected function getEntityManager() + public function getEntityManager() { if (!$this->entityManager) { $moduleOptions = $this->getServiceLocator()->get('unicaen-auth_module_options'); @@ -46,4 +42,4 @@ abstract class AbstractService implements ServiceLocatorAwareInterface return $this->entityManager; } -} +} \ No newline at end of file diff --git a/src/UnicaenAuth/Service/PrivilegeService.php b/src/UnicaenAuth/Service/PrivilegeService.php index 2326e3a6914564a6b972ce011934ee66d6b9ab78..82e29c21e24938bfa9bf0302a0b88a072eab376d 100644 --- a/src/UnicaenAuth/Service/PrivilegeService.php +++ b/src/UnicaenAuth/Service/PrivilegeService.php @@ -2,75 +2,95 @@ namespace UnicaenAuth\Service; -use UnicaenAuth\Entity\Db\Privilege; -use UnicaenAuth\Entity\Db\Role; +use Doctrine\ORM\EntityRepository; +use InvalidArgumentException; +use UnicaenAuth\Entity\Db\PrivilegeInterface; +use UnicaenAuth\Entity\Db\RoleInterface; use UnicaenAuth\Provider\Privilege\PrivilegeProviderInterface; -use \BjyAuthorize\Provider\Resource\ProviderInterface as ResourceProviderInterface; +use BjyAuthorize\Provider\Resource\ProviderInterface as ResourceProviderInterface; use UnicaenAuth\Provider\Privilege\Privileges; -class PrivilegeService extends AbstractService implements PrivilegeProviderInterface, ResourceProviderInterface +class PrivilegeService extends AbstractService + implements PrivilegeProviderInterface, ResourceProviderInterface { + /** + * @var string + */ + protected $privilegeEntityClass; + + /** + * @param string $privilegeEntityClass + */ + public function setPrivilegeEntityClass($privilegeEntityClass) + { + if (! class_exists($privilegeEntityClass) || ! in_array(PrivilegeInterface::class, class_implements($privilegeEntityClass))) { + throw new InvalidArgumentException("La classe spécifiée pour l'entité privilège doit implémenter " . PrivilegeInterface::class); + } + + $this->privilegeEntityClass = $privilegeEntityClass; + } + /** * @var array */ protected $privilegesRoles; - + /** + * @return EntityRepository + */ + public function getRepo() + { + return $this->getEntityManager()->getRepository($this->privilegeEntityClass); + } /** - * @return Privilege[] + * @return PrivilegeInterface[] */ 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(); + $qb = $this->getRepo()->createQueryBuilder('p') + ->addSelect('c') + ->join('p.categorie', 'c') + ->addOrderBy('c.ordre') + ->addOrderBy('p.ordre'); - return $privileges; + return $qb->getQuery()->getResult(); } - - /** * @param $id * - * @return null|Privilege + * @return null|PrivilegeInterface */ public function get($id) { - return $this->getEntityManager()->getRepository('UnicaenAuth\Entity\Db\Privilege')->findOneBy(['id' => $id]); + return $this->getRepo()->findOneBy(['id' => $id]); } - - /** - * @param Privilege $privilege - * @param Role $role + * @param PrivilegeInterface $privilege + * @param RoleInterface $role * * @throws \Doctrine\DBAL\DBALException */ - public function addRole(Privilege $privilege, Role $role) + public function addRole(PrivilegeInterface $privilege, RoleInterface $role) { $privilege->addRole($role); $this->getEntityManager()->flush(); } - - /** - * @param Privilege $privilege - * @param Role $role + * @param PrivilegeInterface $privilege + * @param RoleInterface $role * * @throws \Doctrine\DBAL\DBALException */ - public function removeRole(Privilege $privilege, Role $role) + public function removeRole(PrivilegeInterface $privilege, RoleInterface $role) { $privilege->removeRole($role); $this->getEntityManager()->flush(); } - - /** * Retourne un tableau à deux dimentions composé de chaînes de caractère UNIQUEMENT * @@ -86,20 +106,18 @@ class PrivilegeService extends AbstractService implements PrivilegeProviderInter { 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 */ + + $qb = $this->getRepo()->createQueryBuilder('p') + ->addSelect('c, r') + ->join('p.categorie', 'c') + ->join('p.role', 'r'); + $result = $qb->getQuery()->getResult(); + + foreach ($result as $privilege) { + /* @var $privilege PrivilegeInterface */ $pr = []; - foreach( $privilege->getRole() as $role ){ - /* @var $role Role */ + foreach ($privilege->getRole() as $role) { + /* @var $role RoleInterface */ $pr[] = $role->getRoleId(); } $this->privilegesRoles[$privilege->getFullCode()] = $pr; @@ -109,14 +127,12 @@ class PrivilegeService extends AbstractService implements PrivilegeProviderInter return $this->privilegesRoles; } - - /** * @return array */ public function getResources() { - $resources = []; + $resources = []; $privileges = array_keys($this->getPrivilegesRoles()); foreach ($privileges as $privilege) { $resources[] = Privileges::getResourceId($privilege); @@ -124,5 +140,4 @@ class PrivilegeService extends AbstractService implements PrivilegeProviderInter return $resources; } - -} +} \ No newline at end of file diff --git a/src/UnicaenAuth/Service/PrivilegeServiceFactory.php b/src/UnicaenAuth/Service/PrivilegeServiceFactory.php new file mode 100644 index 0000000000000000000000000000000000000000..04271e3b7121d866e302cba9ece5d006218d2639 --- /dev/null +++ b/src/UnicaenAuth/Service/PrivilegeServiceFactory.php @@ -0,0 +1,25 @@ +<?php + +namespace UnicaenAuth\Service; + +use UnicaenAuth\Entity\Db\Privilege; +use Zend\ServiceManager\FactoryInterface; +use Zend\ServiceManager\ServiceLocatorInterface; + +class PrivilegeServiceFactory implements FactoryInterface +{ + public function createService(ServiceLocatorInterface $serviceLocator) + { + $config = $serviceLocator->get('Config'); + + if (! isset($config['unicaen-auth']['privilege_entity_class'])) { +// throw new InvalidArgumentException("La classe de l'entité privilège n'a pas été trouvée dans la config"); + $config['unicaen-auth']['privilege_entity_class'] = Privilege::class; + } + + $service = new PrivilegeService(); + $service->setPrivilegeEntityClass($config['unicaen-auth']['privilege_entity_class']); + + return $service; + } +} \ No newline at end of file diff --git a/src/UnicaenAuth/Service/RoleService.php b/src/UnicaenAuth/Service/RoleService.php index 162042dd9a966908482262f5e73ebbb500355665..64b2713a5c4be2a748e3b049a3d52b3f5821d602 100644 --- a/src/UnicaenAuth/Service/RoleService.php +++ b/src/UnicaenAuth/Service/RoleService.php @@ -2,9 +2,9 @@ namespace UnicaenAuth\Service; -use Doctrine\Common\Persistence\ObjectRepository; -use UnicaenAuth\Entity\Db\Role; - +use Doctrine\ORM\EntityRepository; +use InvalidArgumentException; +use UnicaenAuth\Entity\Db\RoleInterface; /** * Class RoleService @@ -15,49 +15,59 @@ use UnicaenAuth\Entity\Db\Role; class RoleService extends AbstractService { /** - * @return ObjectRepository + * @var string */ - public function getRepo() + protected $roleEntityClass; + + /** + * @param string $roleEntityClass + */ + public function setRoleEntityClass($roleEntityClass) { - return $this->getEntityManager()->getRepository('UnicaenAuth\Entity\Db\Role'); - } + if (! class_exists($roleEntityClass) || ! in_array(RoleInterface::class, class_implements($roleEntityClass))) { + throw new InvalidArgumentException("La classe spécifiée pour l'entité rôle doit implémenter " . RoleInterface::class); + } + $this->roleEntityClass = $roleEntityClass; + } + /** + * @return EntityRepository + */ + public function getRepo() + { + return $this->getEntityManager()->getRepository($this->roleEntityClass); + } /** - * @return Role[] + * @return RoleInterface[] */ public function getList() { - $dql = 'SELECT r FROM UnicaenAuth\Entity\Db\Role r ORDER BY r.roleId'; - $query = $this->getEntityManager()->createQuery($dql); - $roles = $query->getResult(); + $qb = $this->getRepo()->createQueryBuilder('r')->addOrderBy('r.roleId'); + $roles = $qb->getQuery()->getResult(); return $roles; } - - /** * @param $id * - * @return null|Role + * @return null|RoleInterface */ public function get($id) { return $this->getRepo()->findOneBy(['id' => $id]); } - - /** * Sauvegarde le rôle en BDD * - * @param Role $role - * + * @param RoleInterface $role * @return self + * @throws \Doctrine\ORM\OptimisticLockException */ - public function save(Role $role) + public function save(RoleInterface $role) { $this->getEntityManager()->persist($role); $this->getEntityManager()->flush($role); @@ -65,16 +75,14 @@ class RoleService extends AbstractService return $this; } - - /** * Supprime un rôle * - * @param Role $role - * + * @param RoleInterface $role * @return $this + * @throws \Doctrine\ORM\OptimisticLockException */ - public function delete(Role $role) + public function delete(RoleInterface $role) { $this->getEntityManager()->remove($role); $this->getEntityManager()->flush($role); @@ -82,15 +90,13 @@ class RoleService extends AbstractService return $this; } - - /** * Nouvelle entité * - * @return Role + * @return RoleInterface */ public function newEntity() { - return new Role; + return new $this->roleEntityClass; } -} +} \ No newline at end of file diff --git a/src/UnicaenAuth/Service/RoleServiceFactory.php b/src/UnicaenAuth/Service/RoleServiceFactory.php new file mode 100644 index 0000000000000000000000000000000000000000..74c4057c8d3d7bf455a4459f060d828453e3e84a --- /dev/null +++ b/src/UnicaenAuth/Service/RoleServiceFactory.php @@ -0,0 +1,24 @@ +<?php + +namespace UnicaenAuth\Service; + +use UnicaenAuth\Entity\Db\Role; +use Zend\ServiceManager\FactoryInterface; +use Zend\ServiceManager\ServiceLocatorInterface; + +class RoleServiceFactory implements FactoryInterface +{ + public function createService(ServiceLocatorInterface $serviceLocator) + { + $config = $serviceLocator->get('Config'); + + if (! isset($config['unicaen-auth']['role_entity_class'])) { + $config['unicaen-auth']['role_entity_class'] = Role::class; + } + + $service = new RoleService(); + $service->setRoleEntityClass($config['unicaen-auth']['role_entity_class']); + + return $service; + } +} \ No newline at end of file diff --git a/src/UnicaenAuth/Service/ShibService.php b/src/UnicaenAuth/Service/ShibService.php new file mode 100644 index 0000000000000000000000000000000000000000..902e3f55c0eb97eb5fc52843e8040f68b164762f --- /dev/null +++ b/src/UnicaenAuth/Service/ShibService.php @@ -0,0 +1,175 @@ +<?php + +namespace UnicaenAuth\Service; + +use UnicaenApp\Exception\RuntimeException; +use UnicaenAuth\Entity\Shibboleth\ShibUser; +use UnicaenAuth\Options\ModuleOptions; +use Zend\Mvc\Router\Http\TreeRouteStack; + +/** + * Shibboleth service + * + * @author Unicaen + */ +class ShibService +{ + /** + * @var ModuleOptions + */ + protected $options; + + /** + * @var \UnicaenAuth\Entity\Shibboleth\ShibUser + */ + protected $authenticatedUser; + + /** + * @return string + */ + static public function apacheConfigSnippet() + { + $text = <<<EOS +<Location "/"> + AuthType Shibboleth + ShibRequestSetting requireSession false + Require shibboleth +</Location> +<Location "/auth/shibboleth"> + AuthType Shibboleth + ShibRequestSetting requireSession true + Require shibboleth +</Location> +EOS; + return $text; + } + + /** + * @return boolean + */ + public function isShibbolethEnable() + { + $options = $this->options->getShibboleth(); + + return array_key_exists('enable', $options) && (bool) $options['enable']; + } + + /** + * @return ShibUser|null + */ + public function getAuthenticatedUser() + { + if ($this->authenticatedUser === null) { + if (empty($_SERVER['REMOTE_USER'])) { + return null; + } + $this->authenticatedUser = $this->createShibUser(); + } + + return $this->authenticatedUser; + } + + /** + * @return ShibUser + */ + private function createShibUser() + { + $eppn = $_SERVER['REMOTE_USER']; + + if (isset($_SERVER['supannEtuId'])) { + $id = $_SERVER['supannEtuId']; + } elseif (isset($_SERVER['supannEmpId'])) { + $id = $_SERVER['supannEmpId']; + } else { + throw new RuntimeException('Un au moins des attributs suivants doivent exister dans $_SERVER : supannEtuId, supannEmpId.'); + } + + $mail = null; + if (isset($_SERVER['mail'])) { + $mail = $_SERVER['mail']; + } + + $displayName = null; + if (isset($_SERVER['displayName'])) { + $displayName = $_SERVER['displayName']; + } + + $shibUser = new ShibUser(); + $shibUser->setId($id); + $shibUser->setUsername($eppn); + $shibUser->setDisplayName($displayName); + $shibUser->setEmail($mail); + + return $shibUser; + } + + /** + * Retourne l'URL de déconnexion Shibboleth. + * + * @param string $returnAbsoluteUrl Eventuelle URL *absolue* de retour après déconnexion + * @return string + */ + public function getLogoutUrl($returnAbsoluteUrl = null) + { + $logoutRelativeUrl = '/Shibboleth.sso/Logout?return='; // NB: '?return=' semble obligatoire! + + if ($returnAbsoluteUrl) { + $logoutRelativeUrl .= urlencode($returnAbsoluteUrl); + } + + return $logoutRelativeUrl; + } + + /** + * @param ModuleOptions $options + */ + public function setOptions(ModuleOptions $options) + { + $this->options = $options; + } + + /** + * @param TreeRouteStack $router + */ + public function reconfigureRoutesForShibAuth(TreeRouteStack $router) + { + $router->addRoutes([ + // remplace les routes existantes (cf. config du module) + 'zfcuser' => [ + 'type' => 'Literal', + 'priority' => 1000, + 'options' => [ + 'route' => '/auth', + 'defaults' => [ + 'controller' => 'zfcuser', + 'action' => 'index', + ], + ], + 'may_terminate' => true, + 'child_routes' => [ + 'login' => [ + 'type' => 'Literal', + 'options' => [ + 'route' => '/connexion', + 'defaults' => [ + 'controller' => 'zfcuser', // NB: lorsque l'auth Shibboleth est activée, la page propose + 'action' => 'login', // 2 possibilités d'auth : LDAP et Shibboleth. + ], + ], + ], + 'logout' => [ + 'type' => 'Segment', + 'options' => [ + 'route' => '/:operation/shibboleth/', + 'defaults' => [ + 'controller' => 'UnicaenAuth\Controller\Auth', + 'action' => 'shibboleth', + 'operation' => 'deconnexion' + ], + ], + ], + ], + ], + ]); + } +} \ No newline at end of file diff --git a/src/UnicaenAuth/Service/ShibServiceFactory.php b/src/UnicaenAuth/Service/ShibServiceFactory.php new file mode 100644 index 0000000000000000000000000000000000000000..418f717049ccb1b7477009a156456d05ca9062eb --- /dev/null +++ b/src/UnicaenAuth/Service/ShibServiceFactory.php @@ -0,0 +1,20 @@ +<?php + +namespace UnicaenAuth\Service; + +use UnicaenAuth\Options\ModuleOptions; +use Zend\ServiceManager\ServiceLocatorInterface; + +class ShibServiceFactory +{ + public function __invoke(ServiceLocatorInterface $sl) + { + /** @var ModuleOptions $options */ + $options = $sl->get('unicaen-auth_module_options'); + + $service = new ShibService(); + $service->setOptions($options); + + return $service; + } +} \ No newline at end of file diff --git a/src/UnicaenAuth/Service/Traits/ShibServiceAwareTrait.php b/src/UnicaenAuth/Service/Traits/ShibServiceAwareTrait.php new file mode 100644 index 0000000000000000000000000000000000000000..825e8987bf4197d0d8be28539e73bbb53986f9f0 --- /dev/null +++ b/src/UnicaenAuth/Service/Traits/ShibServiceAwareTrait.php @@ -0,0 +1,21 @@ +<?php + +namespace UnicaenAuth\Service\Traits; + +use UnicaenAuth\Service\ShibService; + +trait ShibServiceAwareTrait +{ + /** + * @var ShibService + */ + protected $shibService; + + /** + * @param ShibService $shibService + */ + public function setShibService(ShibService $shibService) + { + $this->shibService = $shibService; + } +} \ No newline at end of file diff --git a/src/UnicaenAuth/Service/Traits/UserServiceAwareTrait.php b/src/UnicaenAuth/Service/Traits/UserServiceAwareTrait.php new file mode 100644 index 0000000000000000000000000000000000000000..74a268ff27467b748e46a095e0e907b38f90ff07 --- /dev/null +++ b/src/UnicaenAuth/Service/Traits/UserServiceAwareTrait.php @@ -0,0 +1,21 @@ +<?php + +namespace UnicaenAuth\Service\Traits; + +use UnicaenAuth\Service\User as UserService; + +trait UserServiceAwareTrait +{ + /** + * @var UserService + */ + protected $userService; + + /** + * @param UserService $userService + */ + public function setUserService(UserService $userService) + { + $this->userService = $userService; + } +} \ No newline at end of file diff --git a/src/UnicaenAuth/Service/User.php b/src/UnicaenAuth/Service/User.php index c1f2f67ca09721fe917ac1b1ae48d400442d4e2f..180513a7ecefd1e8f9d2641d65de1ff245f84c08 100644 --- a/src/UnicaenAuth/Service/User.php +++ b/src/UnicaenAuth/Service/User.php @@ -1,18 +1,19 @@ <?php + namespace UnicaenAuth\Service; +use UnicaenAuth\Event\UserAuthenticatedEvent; use PDOException; -use UnicaenApp\Exception; +use UnicaenApp\Entity\Ldap\People; +use UnicaenApp\Exception\RuntimeException; use UnicaenApp\Mapper\Ldap\People as LdapPeopleMapper; +use UnicaenAuth\Entity\Shibboleth\ShibUser; 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; use Zend\EventManager\EventManagerInterface; -use ZfcUser\Authentication\Adapter\AdapterChainEvent as AuthEvent; +use Zend\ServiceManager\ServiceLocatorAwareInterface; +use Zend\ServiceManager\ServiceLocatorAwareTrait; +use ZfcUser\Entity\UserInterface; use ZfcUser\Options\AuthenticationOptionsInterface; use ZfcUser\Options\ModuleOptions as ZfcUserModuleOptions; @@ -20,17 +21,13 @@ use ZfcUser\Options\ModuleOptions as ZfcUserModuleOptions; * Service d'enregistrement dans la table des utilisateurs de l'application * de l'utilisateur authentifié avec succès. * - * Est notifié via la méthode 'userAuthenticated()' lorsque l'authentification - * est terminée avec succès. - * * @see \UnicaenAuth\Authentication\Adapter\AbstractFactory - * @author Bertrand GAUTHIER <bertrand.gauthier at unicaen.fr> + * @author Unicaen */ class User implements ServiceLocatorAwareInterface, EventManagerAwareInterface { use ServiceLocatorAwareTrait; - const EVENT_USER_AUTHENTICATED_PRE_PERSIST = 'userAuthenticated.prePersist'; /** @@ -56,14 +53,35 @@ class User implements ServiceLocatorAwareInterface, EventManagerAwareInterface /** * Save authenticated user in database from LDAP data. * + * @param UserInterface|People $userData * @return bool */ - public function userAuthenticated(AuthEvent $e) + public function userAuthenticated($userData) { if (!$this->getOptions()->getSaveLdapUserInDatabase()) { return false; } - if (!($username = $e->getIdentity())) { + + switch (true) { + case $userData instanceof People: + $username = $userData->getSupannAliasLogin(); + $email = $userData->getMail(); + $password = 'ldap'; + $state = in_array('deactivated', ldap_explode_dn($userData->getDn(), 1)) ? 0 : 1; + + break; + case $userData instanceof ShibUser: + $username = $userData->getUsername(); + $email = $userData->getEmail(); + $password = 'shib'; + $state = 1; + break; + default: + throw new RuntimeException("A implémenter!!"); + break; + } + + if (!$username) { return false; } @@ -73,18 +91,13 @@ class User implements ServiceLocatorAwareInterface, EventManagerAwareInterface } if (!is_string($username)) { - throw new Exception("Identité rencontrée inattendue."); - } - - // recherche de l'individu dans l'annuaire LDAP - $ldapPeople = $this->getLdapPeopleMapper()->findOneByUsername($username); - if (!$ldapPeople) { - return false; + throw new RuntimeException("Identité rencontrée inattendue."); } // update/insert de l'utilisateur dans la table de l'appli $mapper = $this->getServiceLocator()->get('zfcuser_user_mapper'); /* @var $mapper \ZfcUserDoctrineORM\Mapper\User */ try { + /** @var UserInterface $entity */ $entity = $mapper->findByUsername($username); if (!$entity) { $entityClass = $this->getZfcUserOptions()->getUserEntityClass(); @@ -95,30 +108,44 @@ class User implements ServiceLocatorAwareInterface, EventManagerAwareInterface else { $method = 'update'; } - $entity->setEmail($ldapPeople->getMail()); - $entity->setDisplayName($ldapPeople->getDisplayName()); - $entity->setPassword('ldap'); - $entity->setState(in_array('deactivated', ldap_explode_dn($ldapPeople->getDn(), 1)) ? 0 : 1); - - // déclenche l'événement donnant aux applications clientes l'opportunité de modifier l'entité - // utilisateur avant qu'elle ne soit persistée - $event = new UserAuthenticatedEvent(UserAuthenticatedEvent::PRE_PERSIST); - $event - ->setDbUser($entity) - ->setLdapUser($ldapPeople) - ->setTarget($this); - $this->getEventManager()->trigger($event); + $entity->setEmail($email); + $entity->setDisplayName($userData->getDisplayName()); + $entity->setPassword($password); + $entity->setState($state); + + // pre-persist + $this->triggerUserAuthenticatedEvent($entity, $userData); // persist $mapper->$method($entity); } catch (PDOException $pdoe) { - throw new Exception("Impossible d'enregistrer l'utilisateur authentifié dans la base de données.", null, $pdoe); + throw new RuntimeException("Impossible d'enregistrer l'utilisateur authentifié dans la base de données.", null, $pdoe); } return true; } + /** + * Déclenche l'événement donnant aux applications clientes l'opportunité de modifier l'entité + * utilisateur avant qu'elle ne soit persistée. + * + * @param mixed $entity + * @param People|ShibUser $userData + */ + private function triggerUserAuthenticatedEvent($entity, $userData) + { + $event = new UserAuthenticatedEvent(UserAuthenticatedEvent::PRE_PERSIST); + $event->setTarget($this); + $event->setDbUser($entity); + if ($userData instanceof People) { + $event->setLdapUser($userData); + } elseif ($userData instanceof ShibUser) { + $event->setShibUser($userData); + } + + $this->getEventManager()->trigger($event); + } /** * Retrieve the event manager @@ -136,7 +163,7 @@ class User implements ServiceLocatorAwareInterface, EventManagerAwareInterface * Inject an EventManager instance * * @param EventManagerInterface $eventManager - * @return void + * @return self */ public function setEventManager(EventManagerInterface $eventManager) { @@ -145,40 +172,18 @@ class User implements ServiceLocatorAwareInterface, EventManagerAwareInterface get_called_class(), ]); $this->eventManager = $eventManager; - return $this; - } - - /** - * get ldap people mapper - * - * @return LdapPeopleMapper - */ - public function getLdapPeopleMapper() - { - if (null === $this->ldapPeopleMapper) { - $this->ldapPeopleMapper = $this->getServiceLocator()->get('ldap_people_mapper'); - } - return $this->ldapPeopleMapper; - } - /** - * set ldap people mapper - * - * @param LdapPeopleMapper $mapper - * @return User - */ - public function setLdapPeopleMapper(LdapPeopleMapper $mapper) - { - $this->ldapPeopleMapper = $mapper; return $this; } /** * @param ModuleOptions $options + * @return self */ public function setOptions(ModuleOptions $options) { $this->options = $options; + return $this; } @@ -190,15 +195,18 @@ class User implements ServiceLocatorAwareInterface, EventManagerAwareInterface if (!$this->options instanceof ModuleOptions) { $this->setOptions($this->getServiceLocator()->get('unicaen-auth_module_options')); } + return $this->options; } /** * @param ZfcUserModuleOptions $options + * @return self */ public function setZfcUserOptions(ZfcUserModuleOptions $options) { $this->zfcUserOptions = $options; + return $this; } @@ -210,6 +218,7 @@ class User implements ServiceLocatorAwareInterface, EventManagerAwareInterface if (!$this->zfcUserOptions instanceof ZfcUserModuleOptions) { $this->setZfcUserOptions($this->getServiceLocator()->get('zfcuser_module_options')); } + return $this->zfcUserOptions; } } \ No newline at end of file diff --git a/src/UnicaenAuth/View/Helper/ShibConnectViewHelper.php b/src/UnicaenAuth/View/Helper/ShibConnectViewHelper.php new file mode 100644 index 0000000000000000000000000000000000000000..2038e8f7d86fc3d34ec46f410663bf1e508b83eb --- /dev/null +++ b/src/UnicaenAuth/View/Helper/ShibConnectViewHelper.php @@ -0,0 +1,48 @@ +<?php + +namespace UnicaenAuth\View\Helper; + +use UnicaenAuth\Service\Traits\ShibServiceAwareTrait; +use Zend\View\Helper\AbstractHelper; +use Zend\View\Renderer\PhpRenderer; + +/** + * Aide de vue dessinant le bouton de connexion via Shibboleth, + * si l'authentification Shibboleth est activée. + * + * @method PhpRenderer getView() + * @author Unicaen + */ +class ShibConnectViewHelper extends AbstractHelper +{ + use ShibServiceAwareTrait; + + /** + * @return string + */ + public function __toString() + { + try { + return $this->render(); + } catch (\Exception $e) { + return '<p>' . $e->getMessage() . '</p><p>' . $e->getTraceAsString() . '</p>'; + } + } + + /** + * @return string + */ + private function render() + { + if (! $this->shibService->isShibbolethEnable()) { + return ''; + } + + $shibUrl = $this->getView()->url('auth/shibboleth', [], ['query' => $this->getView()->queryParams()], true); + + return <<<EOS +Se connecter plutôt avec la +<a href="$shibUrl" class="btn btn-success btn-lg">Fédération d'identité Renater</a> +EOS; + } +} \ No newline at end of file diff --git a/src/UnicaenAuth/View/Helper/ShibConnectViewHelperFactory.php b/src/UnicaenAuth/View/Helper/ShibConnectViewHelperFactory.php new file mode 100644 index 0000000000000000000000000000000000000000..f9828c0e12a42a208f8a3b680f8d9459b7a6cdcf --- /dev/null +++ b/src/UnicaenAuth/View/Helper/ShibConnectViewHelperFactory.php @@ -0,0 +1,24 @@ +<?php + +namespace UnicaenAuth\View\Helper; + +use UnicaenAuth\Service\ShibService; +use Zend\View\HelperPluginManager; + +class ShibConnectViewHelperFactory +{ + /** + * @param HelperPluginManager $hpm + * @return ShibConnectViewHelper + */ + public function __invoke(HelperPluginManager $hpm) + { + /** @var ShibService $shibService */ + $shibService = $hpm->getServiceLocator()->get(ShibService::class); + + $helper = new ShibConnectViewHelper(); + $helper->setShibService($shibService); + + return $helper; + } +} \ No newline at end of file diff --git a/view/unicaen-auth/auth/shibboleth.phtml b/view/unicaen-auth/auth/shibboleth.phtml new file mode 100644 index 0000000000000000000000000000000000000000..63addc60275602b3b9b0d546d1d8adce1b6543ee --- /dev/null +++ b/view/unicaen-auth/auth/shibboleth.phtml @@ -0,0 +1,23 @@ +<h1 class="page-header">Authentification Shibboleth</h1> + +<p> + Si vous arrivez sur cette page, c'est sans doute que vous cherchez à utiliser l'authentification Shibboleth, mais + qu'elle est mal configurée ! +</p> + +<p> + Vous devez activer l'authentification Shibboleth dans la config : +</p> +<pre> + 'unicaen-auth' => [ + ... + 'shibboleth' => [ + 'enable' => true + ], + ]; +</pre> + +<p> + Et voici ce que vous devez ajouter dans la configuration Apache de votre site : +</p> +<pre><?php echo htmlspecialchars(\UnicaenAuth\Service\ShibService::apacheConfigSnippet()) ?></pre> \ No newline at end of file diff --git a/view/zfc-user/user/login.phtml b/view/zfc-user/user/login.phtml index e52f5d7d9a2616b90276777ac6096f0f02160525..99a0546c7f235a2aebfc0a601e23d512d1d5d9c8 100644 --- a/view/zfc-user/user/login.phtml +++ b/view/zfc-user/user/login.phtml @@ -11,48 +11,61 @@ $form->setAttributes([ ?> <style> - #div-connexion { max-width: 350px; margin: auto; } + .div-connexion { max-width: 350px; margin: auto auto 30px; } + .div-connexion h2 { margin: 0; } + .div-connexion .btn-primary { margin: 10px 0; } + .div-connexion .btn-success { margin: 10px 0; display: inline-block; } </style> -<div id="div-connexion"> +<div class="div-connexion panel panel-primary"> - <h1 class="page-header"><?php echo $this->translate("Connexion"); ?></h1> + <div class="panel-heading"> + <h2><?php echo $this->translate("Connexion"); ?></h2> + </div> - <?php echo $this->form()->openTag($form) ?> + <div class="panel-body"> + <?php echo $this->form()->openTag($form) ?> + <?php if (($errors = $this->formErrors($this->loginForm))): ?> + <p><?php echo $errors ?></p> + <?php endif ?> + <p> + <?php + $identity = $form->get($name = 'identity')->setAttributes(['id' => $name, 'class' => 'form-control']); + echo $this->formLabel($identity); + echo $this->formInput($identity); + ?> + </p> + <p> + <?php + $identity = $form->get($name = 'credential')->setAttributes(['id' => $name, 'class' => 'form-control']); + echo $this->formLabel($identity); + echo $this->formInput($identity); + ?> + </p> + <?php if ($this->redirect): ?> + <input type="hidden" name="redirect" value="<?php echo $this->redirect ?>" /> + <?php endif ?> + <p> + <?php echo $this->formButton($form->get('submit')->setAttribute('class', 'btn btn-primary')) ?> + </p> + <?php echo $this->form()->closeTag() ?> - <?php if (($errors = $this->formErrors($this->loginForm))): ?> - <p><?php echo $errors ?></p> - <?php endif ?> + <hr> - <p> - <?php - $identity = $form->get($name = 'identity')->setAttributes(['id' => $name, 'class' => 'form-control']); - echo $this->formLabel($identity); - echo $this->formInput($identity); - ?> - </p> - <p> - <?php - $identity = $form->get($name = 'credential')->setAttributes(['id' => $name, 'class' => 'form-control']); - echo $this->formLabel($identity); - echo $this->formInput($identity); - ?> - </p> - <?php if ($this->redirect): ?> - <input type="hidden" name="redirect" value="<?php echo $this->redirect ?>" /> - <?php endif ?> + <!-- Connexion Shibboleth (si activée) --> + <?php echo $this->shibConnect() ?> + </div> +</div> - <p> - <?php echo $this->formButton($form->get('submit')->setAttribute('class', 'btn btn-primary btn-block')) ?> - </p> - <?php echo $this->form()->closeTag() ?> +<!-- Création d'un compte local (si autorisée) --> +<?php if ($this->enableRegistration) : ?> +<div id="div-connexion" class="panel panel-primary"> + <?php echo $this->translate("Not registered?"); ?> <a href="<?php echo $this->url('zfcuser/register') . ($this->redirect ? '?redirect=' . $this->redirect : '') ?>"><?php echo $this->translate("Sign up!"); ?></a> +</div> +<?php endif; ?> - <?php if ($this->enableRegistration) : ?> - <?php echo $this->translate("Not registered?"); ?> <a href="<?php echo $this->url('zfcuser/register') . ($this->redirect ? '?redirect=' . $this->redirect : '') ?>"><?php echo $this->translate("Sign up!"); ?></a> - <?php endif; ?> -</div> <script type="text/javascript"> // focus sur le 1er champ vide $("input").filter(function() {