Commit 46d117e6 authored by Laurent Lécluse's avatar Laurent Lécluse
Browse files

Merge branch 'master' of https://git.unicaen.fr/lib/unicaen/auth into laminas_migration

 Conflicts:
	src/UnicaenAuth/Authentication/Adapter/Ldap.php
	src/UnicaenAuth/Authentication/Storage/AuthFactory.php
	src/UnicaenAuth/Authentication/Storage/DbFactory.php
	src/UnicaenAuth/Authentication/Storage/LdapFactory.php
	src/UnicaenAuth/Authentication/Storage/ShibFactory.php
	src/UnicaenAuth/Authentication/Storage/UsurpationFactory.php
parents 8644847a 74cd6ed5
CHANGELOG
=========
3.2.8
-----
- [FIX] Données d'authentification : utilisation du SessionManager global pour avoir les durées de conservation des cookies correctes.
3.2.6 / 3.2.7
-----
- Ajout d'un événement avec le détail des erreurs LDAP
3.2.5
-----
- [FIX] Petite correction d'une NOTICE qui apparaissait lorsqu'on se déconnectait.
3.2.3
-----
- [FIX] Meilleure gestion d'erreur en cas de demande d'usurpation d'un compte inexistant : retour à l'accueil + message.
3.2.2
-----
- L'URL de connexion accepte désormais role=ROLE_ID pour sélectionner automatiquement ce rôle une fois authentifié.
......@@ -72,4 +88,4 @@ CHANGELOG
3.0.0 (17/09/2019)
------------------
Première version officielle sous ZF3.
\ No newline at end of file
Première version officielle sous ZF3.
......@@ -10,6 +10,7 @@ use UnicaenAuth\Service\User;
use Laminas\Authentication\Adapter\Ldap as LdapAuthAdapter;
use Laminas\Authentication\Exception\ExceptionInterface;
use Laminas\Authentication\Result as AuthenticationResult;
use Laminas\EventManager\Event;
use Laminas\EventManager\EventInterface;
use Laminas\EventManager\EventManager;
use Laminas\EventManager\EventManagerAwareInterface;
......@@ -24,11 +25,13 @@ use ZfcUser\Authentication\Adapter\AdapterChainEvent;
class Ldap extends AbstractAdapter implements EventManagerAwareInterface
{
use ModuleOptionsAwareTrait;
const TYPE = 'ldap';
const USURPATION_USERNAMES_SEP = '=';
const LDAP_AUTHENTIFICATION_FAIL = 'authentification.ldap.fail';
/**
* @var string
*/
......@@ -88,7 +91,8 @@ class Ldap extends AbstractAdapter implements EventManagerAwareInterface
// NB: Dans la version 3.0.0 de zf-commons/zfc-user, cette méthode prend un EventInterface.
// Mais dans la branche 3.x, c'est un AdapterChainEvent !
// Si un jour c'est un AdapterChainEvent qui est attendu, plus besoin de faire $e->getTarget().
$event = $e->getTarget(); /* @var $event AdapterChainEvent */
$event = $e->getTarget();
/* @var $event AdapterChainEvent */
if ($this->isSatisfied()) {
try {
......@@ -103,7 +107,7 @@ class Ldap extends AbstractAdapter implements EventManagerAwareInterface
return true;
}
$username = $event->getRequest()->getPost()->get('identity');
$username = $event->getRequest()->getPost()->get('identity');
$credential = $event->getRequest()->getPost()->get('credential');
if (function_exists('mb_strtolower')) {
......@@ -115,7 +119,7 @@ class Ldap extends AbstractAdapter implements EventManagerAwareInterface
$success = $this->authenticateUsername($username, $credential);
// Failure!
if (! $success) {
if (!$success) {
$event
->setCode(AuthenticationResult::FAILURE)
->setMessages([/*'LDAP bind failed.'*/]);
......@@ -201,16 +205,33 @@ class Ldap extends AbstractAdapter implements EventManagerAwareInterface
}
// LDAP auth
$result = $this->getLdapAuthAdapter()->setUsername($username)->setPassword($credential)->authenticate();
$result = $this->getLdapAuthAdapter()->setUsername($username)->setPassword($credential)->authenticate();
// Envoi des erreurs LDAP dans un événement
if (!$result->isValid()) {
$messages = "LDAP ERROR : ";
$errorMessages = $result->getMessages();
if (count($errorMessages) > 0) {
// On ne prend que les 2 premières lignes d'erreur (les suivantes contiennent souvent
// les mots de passe de l'utilisateur, et les mot de passe dans les logs... bof bof).
for ($i = 0; $i < 2 && count($errorMessages) >= $i; $i++) {
$messages .= $errorMessages[$i] . " ";
}
}
$errorEvent = new Event(self::LDAP_AUTHENTIFICATION_FAIL, null, ['messages' => $messages]);
$this->getEventManager()->triggerEvent($errorEvent);
}
$success = $result->isValid();
// verif existence du login usurpé
if ($this->usernameUsurpe) {
// s'il nexiste pas, échec de l'authentification
if (!@$this->getLdapAuthAdapter()->getLdap()->searchEntries("(".$this->moduleOptions->getLdapUsername()."=$this->usernameUsurpe)")) {
if (!@$this->getLdapAuthAdapter()->getLdap()->searchEntries(
"(" . $this->moduleOptions->getLdapUsername() . "=$this->usernameUsurpe)"
)) {
$this->usernameUsurpe = null;
$success = false;
$success = false;
}
}
......@@ -293,10 +314,12 @@ class Ldap extends AbstractAdapter implements EventManagerAwareInterface
*/
public function setEventManager(EventManagerInterface $eventManager): self
{
$eventManager->setIdentifiers([
__NAMESPACE__,
__CLASS__,
]);
$eventManager->setIdentifiers(
[
__NAMESPACE__,
__CLASS__,
]
);
$this->eventManager = $eventManager;
return $this;
......
......@@ -4,6 +4,9 @@ namespace UnicaenAuth\Authentication\Storage;
use Interop\Container\ContainerInterface;
use Laminas\Authentication\Storage\Session;
use Laminas\Authentication\Storage\Session;
use Laminas\Session\Exception\RuntimeException;
use Laminas\Session\SessionManager;
class AuthFactory
{
......@@ -14,9 +17,23 @@ class AuthFactory
*/
public function __invoke(ContainerInterface $container, string $requestedName): Auth
{
/** @var SessionManager $sessionManager */
$sessionManager = $container->get(SessionManager::class);
$storage = new Auth();
$storage->setStorage(new Session(Usurpation::class));
try {
$storage->setStorage(new Session(Usurpation::class, null, $sessionManager));
} catch (RuntimeException $e) {
/**
* Tentative de réagir en cas d'erreur suivante :
* "PHP Fatal error: Uncaught Zend\Session\Exception\RuntimeException: Session validation failed in
* /var/www/sygal/vendor/zendframework/zend-session/src/SessionManager.php:160"
*/
$sessionManager->regenerateId(true);
$storage->setStorage(new Session(Usurpation::class, null, $sessionManager));
}
return $storage;
}
}
\ No newline at end of file
}
......@@ -6,6 +6,7 @@ use Interop\Container\ContainerInterface;
use UnicaenAuth\Authentication\Adapter\Db as DbAdapter;
use UnicaenAuth\Options\ModuleOptions;
use Laminas\Authentication\Storage\Session;
use Laminas\Session\SessionManager;
use ZfcUser\Mapper\UserInterface as UserMapper;
class DbFactory
......@@ -24,8 +25,11 @@ class DbFactory
/** @var ModuleOptions $moduleOptions */
$moduleOptions = $container->get('unicaen-auth_module_options');
/** @var SessionManager $sessionManager */
$sessionManager = $container->get(SessionManager::class);
$storage = new Db();
$storage->setStorage(new Session(DbAdapter::class));
$storage->setStorage(new Session(DbAdapter::class, null, $sessionManager));
$storage->setMapper($mapper);
$storage->setModuleOptions($moduleOptions);
......
......@@ -7,6 +7,7 @@ use UnicaenApp\Mapper\Ldap\People as LdapPeopleMapper;
use UnicaenAuth\Authentication\Adapter\Ldap as LdapAdapter;
use UnicaenAuth\Options\ModuleOptions;
use Laminas\Authentication\Storage\Session;
use Laminas\Session\SessionManager;
class LdapFactory
{
......@@ -18,8 +19,11 @@ class LdapFactory
/** @var ModuleOptions $moduleOptions */
$moduleOptions = $container->get('unicaen-auth_module_options');
/** @var SessionManager $sessionManager */
$sessionManager = $container->get(SessionManager::class);
$storage = new Ldap();
$storage->setStorage(new Session(LdapAdapter::class));
$storage->setStorage(new Session(LdapAdapter::class, null, $sessionManager));
$storage->setMapper($mapper);
$storage->setModuleOptions($moduleOptions);
......
......@@ -6,6 +6,7 @@ use Interop\Container\ContainerInterface;
use UnicaenAuth\Options\ModuleOptions;
use UnicaenAuth\Service\ShibService;
use Laminas\Authentication\Storage\Session;
use Laminas\Session\SessionManager;
class ShibFactory
{
......@@ -23,8 +24,11 @@ class ShibFactory
/** @var ModuleOptions $moduleOptions */
$moduleOptions = $container->get('unicaen-auth_module_options');
/** @var SessionManager $sessionManager */
$sessionManager = $container->get(SessionManager::class);
$storage = new Shib();
$storage->setStorage(new Session(\UnicaenAuth\Authentication\Adapter\Shib::class));
$storage->setStorage(new Session(\UnicaenAuth\Authentication\Adapter\Shib::class, null, $sessionManager));
$storage->setShibService($shibService);
$storage->setModuleOptions($moduleOptions);
......
......@@ -5,6 +5,7 @@ namespace UnicaenAuth\Authentication\Storage;
use Interop\Container\ContainerInterface;
use UnicaenAuth\Options\ModuleOptions;
use Laminas\Authentication\Storage\Session;
use Laminas\Session\SessionManager;
use ZfcUser\Mapper\UserInterface as UserMapper;
class UsurpationFactory
......@@ -23,8 +24,11 @@ class UsurpationFactory
/** @var ModuleOptions $moduleOptions */
$moduleOptions = $container->get('unicaen-auth_module_options');
/** @var SessionManager $sessionManager */
$sessionManager = $container->get(SessionManager::class);
$storage = new Usurpation();
$storage->setStorage(new Session(Usurpation::class));
$storage->setStorage(new Session(Usurpation::class, null, $sessionManager));
$storage->setMapper($mapper);
$storage->setModuleOptions($moduleOptions);
......
......@@ -2,6 +2,7 @@
namespace UnicaenAuth\Controller;
use Exception;
use UnicaenApp\Exception\RuntimeException;
use UnicaenApp\Mapper\Ldap\People as LdapPeopleMapper;
use UnicaenAuth\Entity\Db\AbstractUser;
......@@ -132,10 +133,19 @@ class UtilisateurController extends AbstractActionController
return $this->redirect()->toRoute('home');
}
$utilisateurUsurpe = $this->getUserMapper()->findByUsername($usernameUsurpe); /** @var AbstractUser $utilisateurUsurpe */
if ($utilisateurUsurpe === null) {
$this->flashMessenger()->addErrorMessage(
"La demande d'usurpation du compte '$usernameUsurpe' a échoué car aucun compte utilisateur correspondant " .
"n'a été trouvé."
);
return $this->redirect()->toRoute('home');
}
$sessionIdentity = $this->serviceUserContext->usurperIdentite($usernameUsurpe);
if ($sessionIdentity !== null) {
// cuisine spéciale si l'utilisateur courant s'est authentifié via Shibboleth
$this->usurperIdentiteShib($usernameUsurpe);
$this->usurperIdentiteShib($utilisateurUsurpe);
}
return $this->redirect()->toRoute('home');
......@@ -144,19 +154,15 @@ class UtilisateurController extends AbstractActionController
/**
* Cuisine spéciale pour l'usurpation si l'utilisateur courant s'est authentifié via Shibboleth.
*
* @param string $usernameUsurpe Ex tartempion@unicaen.fr
* @param AbstractUser $utilisateurUsurpe Utilisateur à usurper
*/
protected function usurperIdentiteShib(string $usernameUsurpe)
protected function usurperIdentiteShib(AbstractUser $utilisateurUsurpe)
{
$currentIdentityArray = $this->serviceUserContext->getIdentity();
if (isset($currentIdentityArray['shib']) && $currentIdentityArray['shib'] instanceof ShibUser) {
$fromShibUser = $currentIdentityArray['shib'];
$toUtilisateur = $this->getUserMapper()->findByUsername($usernameUsurpe); /** @var AbstractUser $toUtilisateur */
if ($toUtilisateur === null) {
throw new RuntimeException("L'utilisateur '$usernameUsurpe' n'existe pas dans la table des utilisateurs");
}
$this->shibService->activateUsurpation($fromShibUser, $toUtilisateur);
$this->shibService->activateUsurpation($fromShibUser, $utilisateurUsurpe);
}
}
......
......@@ -335,12 +335,15 @@ class UserContext extends AbstractService implements EventManagerAwareInterface
unset($this->getSessionContainer()->selectedIdentityRole);
}
$role = $this->getSelectableIdentityRoles()[$role];
if ($role instanceof AbstractRole) {
$this->saveUserLastRole($role);
}
$selectableIdentityRoles = $this->getSelectableIdentityRoles();
if (isset($selectableIdentityRoles[$role])){
$role = $selectableIdentityRoles[$role];
if ($role instanceof AbstractRole) {
$this->saveUserLastRole($role);
}
$this->triggerUserRoleSelectedEvent(UserRoleSelectedEvent::POST_SELECTION, $role);
$this->triggerUserRoleSelectedEvent(UserRoleSelectedEvent::POST_SELECTION, $role);
}
return $this;
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment