Skip to content
Snippets Groups Projects
Commit 1ef203f0 authored by Bertrand Gauthier's avatar Bertrand Gauthier
Browse files

Possibilité d'activer ou non (en config) les logs des échecs d'authentification LDAP

parent 74cd6ed5
No related branches found
No related tags found
No related merge requests found
Pipeline #11739 passed
CHANGELOG
=========
3.2.10
-----
- Possibilité d'activer ou non (en config) les logs des échecs d'authentification LDAP.
3.2.8
-----
- [FIX] Données d'authentification : utilisation du SessionManager global pour avoir les durées de conservation des cookies correctes.
......
......@@ -2,20 +2,37 @@
namespace UnicaenAuth;
use UnicaenAuth\Event\Listener\LdapAuthenticationFailureLoggerListener;
use UnicaenAuth\Options\ModuleOptions;
use Zend\EventManager\EventInterface;
use Zend\ModuleManager\Feature\AutoloaderProviderInterface;
use Zend\ModuleManager\Feature\BootstrapListenerInterface;
use Zend\ModuleManager\Feature\ConfigProviderInterface;
use Zend\ModuleManager\Feature\ServiceProviderInterface;
use ZfcUser\Form\Login;
use ZfcUser\Form\LoginFilter;
use Zend\Mvc\MvcEvent;
/**
* Point d'entrée du module d'authentification Unicaen.
*
* @author Bertrand GAUTHIER <bertrand.gauthier@unicaen.fr>
*/
class Module implements AutoloaderProviderInterface, ConfigProviderInterface, ServiceProviderInterface
class Module implements AutoloaderProviderInterface, ConfigProviderInterface, ServiceProviderInterface, BootstrapListenerInterface
{
/**
* @var \UnicaenAuth\Options\ModuleOptions
*/
private $moduleOptions;
/**
* @var \Zend\EventManager\EventManagerInterface
*/
private $eventManager;
/**
* @var \Zend\ServiceManager\ServiceManager
*/
private $serviceManager;
/**
* @return array
* @see ConfigProviderInterface
......@@ -41,16 +58,30 @@ 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.
*
* @param EventInterface $e
*
* @see BootstrapListenerInterface
* @inheritDoc
*/
public function onBootstrap(EventInterface $e)
{
if ($e instanceof MvcEvent) {
/** @var \Zend\Mvc\Application $application */
$application = $e->getApplication();
$this->serviceManager = $application->getServiceManager();
$this->eventManager = $application->getEventManager();
$this->moduleOptions = $this->serviceManager->get(ModuleOptions::class);
$this->attachEventListeners();
}
}
protected function attachEventListeners()
{
// log éventuel des erreurs d'authentification LDAP
$logLdapAuthenticationFailure = $this->moduleOptions->getLdap()['log_failures'] ?? false;
if ($logLdapAuthenticationFailure) {
/** @var LdapAuthenticationFailureLoggerListener $listener */
$listener = $this->serviceManager->get(LdapAuthenticationFailureLoggerListener::class);
$listener->attach($this->eventManager);
}
}
/**
......
......@@ -24,6 +24,8 @@ use UnicaenAuth\Controller\AuthController;
use UnicaenAuth\Controller\AuthControllerFactory;
use UnicaenAuth\Controller\DroitsControllerFactory;
use UnicaenAuth\Controller\UtilisateurControllerFactory;
use UnicaenAuth\Event\Listener\LdapAuthenticationFailureLoggerListener;
use UnicaenAuth\Event\Listener\LdapAuthenticationFailureLoggerListenerFactory;
use UnicaenAuth\Form\CasLoginForm;
use UnicaenAuth\Form\CasLoginFormFactory;
use UnicaenAuth\Form\Droits\RoleFormFactory;
......@@ -155,6 +157,8 @@ $settings = [
'enabled' => true,
'adapter' => Ldap::class,
'form' => LoginForm::class,
'log_failures' => false, /** @see \UnicaenAuth\Event\Listener\LdapAuthenticationFailureLoggerListener */
],
],
......@@ -701,7 +705,9 @@ return [
'UnicaenApp\HistoriqueListener' => HistoriqueListenerFactory::class,
'UnicaenAuth\HistoriqueListener' => HistoriqueListenerFactory::class,
\UnicaenAuth\Event\EventManager::class => \UnicaenAuth\Event\EventManagerFactory::class
\UnicaenAuth\Event\EventManager::class => \UnicaenAuth\Event\EventManagerFactory::class,
LdapAuthenticationFailureLoggerListener::class => LdapAuthenticationFailureLoggerListenerFactory::class,
],
'lazy_services' => [
// Mapping services to their class names is required since the ServiceManager is not a declarative DIC.
......
......@@ -57,6 +57,11 @@ return [
*/
'ldap' => [
'enabled' => true,
/**
* Activation ou non des logs (via `error_log` par défaut) à propos des échecs d'authentification LDAP.
*/
'log_failures' => false, /** @see \UnicaenAuth\Event\Listener\LdapAuthenticationFailureLoggerListener */
],
],
......
......@@ -206,23 +206,21 @@ class Ldap extends AbstractAdapter implements EventManagerAwareInterface
// LDAP auth
$result = $this->getLdapAuthAdapter()->setUsername($username)->setPassword($credential)->authenticate();
$success = $result->isValid();
// Déclenchement d'un événement contenant le nécessaire pour réagir à l'échec d'authentification (log, etc.)
if (!$success) {
$errorEvent = new Event(self::LDAP_AUTHENTIFICATION_FAIL, $this, [
'result' => $result,
'username' => $username,
// Envoi des erreurs LDAP dans un événement
if (!$result->isValid()) {
$messages = "LDAP ERROR : ";
$errorMessages = $result->getMessages();
if (count($errorMessages) > 0) {
// Clé conservée pour compatibilité :
'messages' => implode(PHP_EOL, array_slice($result->getMessages(), 0, 2)),
// 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] . " ";
}
// les mots de passe de l'utilisateur, et les mots de passe dans les logs... bof bof).
]);
$this->eventManager->triggerEvent($errorEvent);
}
$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) {
......
<?php
namespace UnicaenAuth\Event\Listener;
use Psr\Log\LoggerInterface;
use UnicaenAuth\Authentication\Adapter\Ldap;
use Zend\Authentication\Result;
use Zend\EventManager\Event;
use Zend\EventManager\EventManagerInterface;
use Zend\EventManager\ListenerAggregateInterface;
use Zend\EventManager\ListenerAggregateTrait;
/**
* Permet de scruter les erreurs d'authentification LDAP pour les ajouter aux logs.
*
* @author Bertrand GAUTHIER <bertrand.gauthier at unicaen.fr>
*/
class LdapAuthenticationFailureLoggerListener implements ListenerAggregateInterface
{
use ListenerAggregateTrait;
/**
* @var \Psr\Log\LoggerInterface
*/
private $logger;
public function setLogger(LoggerInterface $logger): self
{
$this->logger = $logger;
return $this;
}
public function attach(EventManagerInterface $events, $priority = 1)
{
$this->listeners[] = $events->getSharedManager()->attach(
"*",
Ldap::LDAP_AUTHENTIFICATION_FAIL,
[$this, "onLdapError"],
100
);
}
public function onLdapError(Event $event)
{
/** @var \Zend\Authentication\Result $result */
$result = $event->getParam('result');
$details = $result->getMessages() ?: ["Aucun détail supplémentaire."];
$username = $event->getParam('username');
$messages = [];
switch ($result->getCode()) {
case Result::FAILURE_IDENTITY_NOT_FOUND:
$messages[] = "Identifiant de connexion inconnu : '$username'.";
break;
case Result::FAILURE_CREDENTIAL_INVALID:
$messages[] = "Mot de passe incorrect pour l'identifiant de connexion '$username'.";
break;
case Result::FAILURE:
default:
$messages[] = "Erreur rencontrée lors de l'authentification : ";
break;
}
$messages = array_merge($messages, $details);
$error = "[SyGAL LDAP AUTH] " . implode(PHP_EOL, $messages);
$this->log($error);
}
protected function log(string $message)
{
if ($this->logger !== null) {
$this->logger->error($message);
} else {
error_log($message);
}
}
}
\ No newline at end of file
<?php
namespace UnicaenAuth\Event\Listener;
use Interop\Container\ContainerInterface;
class LdapAuthenticationFailureLoggerListenerFactory
{
public function __invoke(ContainerInterface $container): LdapAuthenticationFailureLoggerListener
{
return new LdapAuthenticationFailureLoggerListener();
}
}
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment