Commit abb31635 authored by Bertrand Gauthier's avatar Bertrand Gauthier
Browse files

Possibilité de connaître la source de l'authentification (db, ldap, cas, shib).

Amélioration de l'usurpation d'identité, possibilité de stopper l'usurpation en cours.
parent ea6cd554
Pipeline #9329 passed with stage
in 1 minute and 13 seconds
...@@ -38,6 +38,8 @@ Première version officielle sous ZF3. ...@@ -38,6 +38,8 @@ Première version officielle sous ZF3.
----- -----
- Aide de vue UserUsurpationHelper : ajout de la possibilité de dessiner un simple bouton. - Aide de vue UserUsurpationHelper : ajout de la possibilité de dessiner un simple bouton.
3.1.3 3.2.0
----- -----
- [FIX] Usurpation d'un compte local en BDD - Possibilité de connaître la source de l'authentification (db, ldap, cas, shib).
- Possibilité de stopper l'usurpation en cours pour revenir à l'identité d'origine.
- [FIX] Usurpation d'un compte local en BDD.
...@@ -75,15 +75,6 @@ class Module implements AutoloaderProviderInterface, ConfigProviderInterface, Se ...@@ -75,15 +75,6 @@ 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 Login(null, $options);
$form->setInputFilter(new LoginFilter($options));
$form->get('identity')->setLabel("Username");
return $form;
},
], ],
]; ];
} }
......
<?php <?php
use UnicaenAuth\Authentication\Adapter\AdapterChainServiceFactory; use UnicaenAuth\Authentication\Adapter\AdapterChainServiceFactory;
use UnicaenAuth\Authentication\Adapter\Cas;
use UnicaenAuth\Authentication\Adapter\CasAdapterFactory; use UnicaenAuth\Authentication\Adapter\CasAdapterFactory;
use UnicaenAuth\Authentication\Adapter\Db;
use UnicaenAuth\Authentication\Adapter\DbAdapterFactory; use UnicaenAuth\Authentication\Adapter\DbAdapterFactory;
use UnicaenAuth\Authentication\Adapter\Ldap;
use UnicaenAuth\Authentication\Adapter\LdapAdapterFactory; use UnicaenAuth\Authentication\Adapter\LdapAdapterFactory;
use UnicaenAuth\Authentication\Adapter\LocalAdapter;
use UnicaenAuth\Authentication\Adapter\LocalAdapterFactory;
use UnicaenAuth\Authentication\Adapter\Shib;
use UnicaenAuth\Authentication\Adapter\ShibAdapterFactory; use UnicaenAuth\Authentication\Adapter\ShibAdapterFactory;
use UnicaenAuth\Authentication\Storage\Auth;
use UnicaenAuth\Authentication\Storage\AuthFactory;
use UnicaenAuth\Authentication\Storage\DbFactory; use UnicaenAuth\Authentication\Storage\DbFactory;
use UnicaenAuth\Authentication\Storage\LdapFactory; use UnicaenAuth\Authentication\Storage\LdapFactory;
use UnicaenAuth\Authentication\Storage\ShibFactory; use UnicaenAuth\Authentication\Storage\ShibFactory;
use UnicaenAuth\Authentication\Storage\Usurpation;
use UnicaenAuth\Authentication\Storage\UsurpationFactory;
use UnicaenAuth\Controller\AuthControllerFactory; use UnicaenAuth\Controller\AuthControllerFactory;
use UnicaenAuth\Controller\DroitsControllerFactory; use UnicaenAuth\Controller\DroitsControllerFactory;
use UnicaenAuth\Controller\UtilisateurControllerFactory; use UnicaenAuth\Controller\UtilisateurControllerFactory;
use UnicaenAuth\Form\CasLoginForm; use UnicaenAuth\Form\CasLoginForm;
use UnicaenAuth\Form\CasLoginFormFactory; use UnicaenAuth\Form\CasLoginFormFactory;
use UnicaenAuth\Form\Droits\RoleFormFactory; use UnicaenAuth\Form\Droits\RoleFormFactory;
use UnicaenAuth\Form\LoginFormFactory;
use UnicaenAuth\Form\LoginForm;
use UnicaenAuth\Form\ShibLoginForm; use UnicaenAuth\Form\ShibLoginForm;
use UnicaenAuth\Form\ShibLoginFormFactory; use UnicaenAuth\Form\ShibLoginFormFactory;
use UnicaenAuth\Guard\PrivilegeControllerFactory; use UnicaenAuth\Guard\PrivilegeControllerFactory;
...@@ -59,9 +71,9 @@ use Zend\ServiceManager\Proxy\LazyServiceFactory; ...@@ -59,9 +71,9 @@ use Zend\ServiceManager\Proxy\LazyServiceFactory;
$settings = [ $settings = [
/** /**
* Configuration de l'authentification via la fédération d'identité (Shibboleth). * Configuration de l'authentification centralisée (CAS).
*/ */
'shib' => [ 'cas' => [
/** /**
* Ordre d'affichage du formulaire de connexion. * Ordre d'affichage du formulaire de connexion.
*/ */
...@@ -70,12 +82,77 @@ $settings = [ ...@@ -70,12 +82,77 @@ $settings = [
/** /**
* Activation ou non de ce mode d'authentification. * Activation ou non de ce mode d'authentification.
*/ */
'enabled' => false, 'enabled' => true,
/**
* Description facultative de ce mode d'authentification qui apparaîtra sur la page de connexion.
*/
'description' => "Cliquez sur le bouton ci-dessous pour accéder à l'authentification centralisée.",
/**
* Adapter compétent pour réaliser l'authentification de l'utilisateur.
*/
'adapter' => Cas::class,
/**
* Service/formulaire d'authentification à utiliser.
*/
'form' => CasLoginForm::class,
/**
* Infos de connexion au serveur CAS.
*/
'connection' => [
'default' => [
'params' => [
'hostname' => 'host.domain.fr',
'port' => 443,
'version' => "2.0",
'uri' => "",
'debug' => false,
],
],
]
],
/**
* Configuration de l'authentification locale (compte LDAP établissement, ou compte BDD application).
*/
'local' => [
'order' => 2,
'enabled' => true,
'description' => "Utilisez ce formulaire si vous possédez un compte LDAP établissement ou un compte local dédié à l'application.",
'form' => LoginForm::class,
/**
* Mode d'authentification à l'aide d'un compte dans la BDD de l'application.
*/
'db' => [
'enabled' => true, // doit être activé pour que l'usurpation fonctionne (cf. Authentication/Storage/Db::read()) :-/ todo: faire mieux
'adapter' => Db::class,
'form' => LoginForm::class,
],
/** /**
* Description facultative de ce mode d'authentification qui apparaîtra sur le formulaire de connexion. * Mode d'authentification à l'aide d'un compte LDAP.
*/ */
'ldap' => [
'enabled' => true,
'adapter' => Ldap::class,
'form' => LoginForm::class,
],
],
/**
* Configuration de l'authentification via la fédération d'identité (Shibboleth).
*/
'shib' => [
'order' => 3,
'enabled' => false,
'description' => "Cliquez sur le bouton ci-dessous pour accéder à l'authentification via la fédération d'identité.", 'description' => "Cliquez sur le bouton ci-dessous pour accéder à l'authentification via la fédération d'identité.",
'adapter' => Shib::class,
'form' => ShibLoginForm::class,
/** /**
* URL de déconnexion. * URL de déconnexion.
...@@ -112,68 +189,6 @@ $settings = [ ...@@ -112,68 +189,6 @@ $settings = [
*/ */
], ],
/**
* Configuration de l'authentification LDAP (compte établissement).
*/
'ldap' => [
'order' => 2,
'enabled' => true,
'description' => "Utilisez ce formulaire pour vous connecter avec votre compte numérique établissement.",
/**
* Type de substitution.
* Permet de "fusionner" les types d'authentification locale (db) et établissement (ldap) et donc leurs
* formulaires de connexion respectifs.
*/
'type' => 'local',
],
/**
* Configuration de l'authentification locale (compte propre à l'appli).
*/
'db' => [
'order' => 3,
'enabled' => false,
/**
* Type de substitution.
* Permet de "grouper" les types d'authentification locale (db) et établissement (ldap) sous un même
* formulaire de connexion.
*/
'type' => 'local',
/**
* Description facultative de ce mode d'authentification qui apparaîtra sur le formulaire d'authentification.
* NB: si la valeur de 'order' pour le type 'db' est supérieure à celle pour le type 'ldap',
* c'est cette description qui sera visible.
*/
'description' => "Utilisez ce formulaire si vous possédez un compte local propre à l'application.",
],
/**
* Configuration de l'authentification centralisée (CAS).
*/
'cas' => [
'order' => 4,
'enabled' => false,
'description' => "Cliquez sur le bouton ci-dessous pour accéder à l'authentification centralisée.",
/**
* Infos de connexion au serveur CAS.
*/
'connection' => [
'default' => [
'params' => [
'hostname' => 'host.domain.fr',
'port' => 443,
'version' => "2.0",
'uri' => "",
'debug' => false,
],
],
]
],
/** /**
* Fournisseurs d'identité. * Fournisseurs d'identité.
*/ */
...@@ -239,9 +254,8 @@ return [ ...@@ -239,9 +254,8 @@ return [
* Default value: array containing 'ZfcUser\Authentication\Adapter\Db' with priority 100 * Default value: array containing 'ZfcUser\Authentication\Adapter\Db' with priority 100
* Accepted values: array containing services that implement 'ZfcUser\Authentication\Adapter\ChainableAdapter' * Accepted values: array containing services that implement 'ZfcUser\Authentication\Adapter\ChainableAdapter'
*/ */
'auth_adapters' => [ 'auth_adapters' => [
300 => 'UnicaenAuth\Authentication\Adapter\Ldap', 400 => LocalAdapter::class, // délègue à Db et Ldap
200 => 'UnicaenAuth\Authentication\Adapter\Db',
100 => 'UnicaenAuth\Authentication\Adapter\Cas', 100 => 'UnicaenAuth\Authentication\Adapter\Cas',
50 => 'UnicaenAuth\Authentication\Adapter\Shib', 50 => 'UnicaenAuth\Authentication\Adapter\Shib',
], ],
...@@ -295,6 +309,8 @@ return [ ...@@ -295,6 +309,8 @@ return [
['controller' => 'UnicaenApp\Controller\Application', 'action' => 'informatique-et-libertes', 'roles' => 'guest'], ['controller' => 'UnicaenApp\Controller\Application', 'action' => 'informatique-et-libertes', 'roles' => 'guest'],
['controller' => 'UnicaenApp\Controller\Application', 'action' => 'refresh-session', 'roles' => 'guest'], ['controller' => 'UnicaenApp\Controller\Application', 'action' => 'refresh-session', 'roles' => 'guest'],
['controller' => 'UnicaenAuth\Controller\Utilisateur', 'action' => 'selectionner-profil', 'roles' => 'guest'], ['controller' => 'UnicaenAuth\Controller\Utilisateur', 'action' => 'selectionner-profil', 'roles' => 'guest'],
['controller' => 'UnicaenAuth\Controller\Utilisateur', 'action' => 'usurper-identite', 'roles' => 'guest'],
['controller' => 'UnicaenAuth\Controller\Utilisateur', 'action' => 'stopper-usurpation', 'roles' => 'guest'],
['controller' => 'UnicaenAuth\Controller\Auth', 'action' => 'login', 'roles' => 'guest'], ['controller' => 'UnicaenAuth\Controller\Auth', 'action' => 'login', 'roles' => 'guest'],
['controller' => 'UnicaenAuth\Controller\Auth', 'action' => 'authenticate', 'roles' => 'guest'], ['controller' => 'UnicaenAuth\Controller\Auth', 'action' => 'authenticate', 'roles' => 'guest'],
...@@ -575,6 +591,7 @@ return [ ...@@ -575,6 +591,7 @@ return [
// in /var/www/sygal/module/Application/src/Application/Controller/UtilisateurController.php on line 34 // in /var/www/sygal/module/Application/src/Application/Controller/UtilisateurController.php on line 34
'service_manager' => [ 'service_manager' => [
'aliases' => [ 'aliases' => [
'zfcuser_login_form' => LoginForm::class,
'Zend\Authentication\AuthenticationService' => 'zfcuser_auth_service', 'Zend\Authentication\AuthenticationService' => 'zfcuser_auth_service',
'UnicaenAuth\Privilege\PrivilegeProvider' => 'UnicaenAuth\Service\Privilege', 'UnicaenAuth\Privilege\PrivilegeProvider' => 'UnicaenAuth\Service\Privilege',
'\UnicaenAuth\Guard\PrivilegeController' => 'UnicaenAuth\Guard\PrivilegeController', '\UnicaenAuth\Guard\PrivilegeController' => 'UnicaenAuth\Guard\PrivilegeController',
...@@ -607,6 +624,7 @@ return [ ...@@ -607,6 +624,7 @@ return [
'UnicaenAuth\Service\UserContext' => UserContextFactory::class, 'UnicaenAuth\Service\UserContext' => UserContextFactory::class,
'zfcuser_user_mapper' => UserMapperFactory::class, 'zfcuser_user_mapper' => UserMapperFactory::class,
'MouchardCompleterAuth' => 'UnicaenAuth\Mouchard\MouchardCompleterAuthFactory', 'MouchardCompleterAuth' => 'UnicaenAuth\Mouchard\MouchardCompleterAuthFactory',
LocalAdapter::class => LocalAdapterFactory::class,
'UnicaenAuth\Authentication\Adapter\Ldap' => LdapAdapterFactory::class, 'UnicaenAuth\Authentication\Adapter\Ldap' => LdapAdapterFactory::class,
'UnicaenAuth\Authentication\Adapter\Db' => DbAdapterFactory::class, 'UnicaenAuth\Authentication\Adapter\Db' => DbAdapterFactory::class,
'UnicaenAuth\Authentication\Adapter\Cas' => CasAdapterFactory::class, 'UnicaenAuth\Authentication\Adapter\Cas' => CasAdapterFactory::class,
...@@ -614,11 +632,16 @@ return [ ...@@ -614,11 +632,16 @@ return [
'UnicaenAuth\Authentication\Storage\Db' => DbFactory::class, 'UnicaenAuth\Authentication\Storage\Db' => DbFactory::class,
'UnicaenAuth\Authentication\Storage\Ldap' => LdapFactory::class, 'UnicaenAuth\Authentication\Storage\Ldap' => LdapFactory::class,
'UnicaenAuth\Authentication\Storage\Shib' => ShibFactory::class, 'UnicaenAuth\Authentication\Storage\Shib' => ShibFactory::class,
Usurpation::class => UsurpationFactory::class,
Auth::class => AuthFactory::class,
'UnicaenAuth\Service\User' => UserFactory::class, 'UnicaenAuth\Service\User' => UserFactory::class,
'UnicaenAuth\Guard\PrivilegeController' => PrivilegeControllerFactory::class, 'UnicaenAuth\Guard\PrivilegeController' => PrivilegeControllerFactory::class,
'UnicaenAuth\Guard\PrivilegeRoute' => PrivilegeRouteFactory::class, 'UnicaenAuth\Guard\PrivilegeRoute' => PrivilegeRouteFactory::class,
'UnicaenAuth\Provider\Rule\PrivilegeRuleProvider' => PrivilegeRuleProviderFactory::class, 'UnicaenAuth\Provider\Rule\PrivilegeRuleProvider' => PrivilegeRuleProviderFactory::class,
// verrue pour forcer le label de l'identifiant qqsoit l'options 'auth_identity_fields'
LoginForm::class => LoginFormFactory::class,
CasLoginForm::class => CasLoginFormFactory::class, CasLoginForm::class => CasLoginFormFactory::class,
ShibLoginForm::class => ShibLoginFormFactory::class, ShibLoginForm::class => ShibLoginFormFactory::class,
'ZfcUser\Authentication\Adapter\AdapterChain' => AdapterChainServiceFactory::class, 'ZfcUser\Authentication\Adapter\AdapterChain' => AdapterChainServiceFactory::class,
......
<?php <?php
use UnicaenAuth\Authentication\Adapter\Shib;
use UnicaenAuth\Authentication\Adapter\Cas;
use UnicaenAuth\Authentication\Adapter\Ldap;
use UnicaenAuth\Authentication\Adapter\Db;
return [ return [
'unicaen-auth' => [ 'unicaen-auth' => [
/** /**
* Authentification LDAP (compte établissement). * Configuration de l'authentification centralisée (CAS).
*/ */
'ldap' => [ 'cas' => [
/** /**
* Ordre d'affichage du formulaire de connexion. * Ordre d'affichage du formulaire de connexion.
*/ */
...@@ -23,39 +18,9 @@ return [ ...@@ -23,39 +18,9 @@ return [
'enabled' => true, 'enabled' => true,
/** /**
* Type de substitution. * Description facultative de ce mode d'authentification qui apparaîtra sur la page de connexion.
* Permet de "fusionner" les types d'authentification applicative (db) et établissement (ldap) et donc leurs
* formulaires de connexion respectifs.
*/
'type' => 'local',
/**
* Description facultative de ce mode d'authentification qui apparaîtra sur le formulaire de connexion.
*/ */
'description' => "Utilisez ce formulaire si vous possédez un compte établissement.", 'description' => "Cliquez sur le bouton ci-dessous pour accéder à l'authentification centralisée.",
],
/**
* Authentification BDD (compte dédié à l'appli).
*/
'db' => [
'order' => 2,
'enabled' => true,
'type' => 'local',
/**
* Description facultative de ce mode d'authentification qui apparaîtra sur le formulaire d'authentification.
* (NB: Si l'authentification LDAP est également activée, c'est cette description qui sera utilisée)
*/
'description' => "Utilisez ce formulaire si vous possédez un compte local dédié à cette application.",
],
/**
* Authentification centralisée (CAS).
*/
'cas' => [
'order' => 3,
'enabled' => false,
/** /**
* Infos de connexion au serveur CAS. * Infos de connexion au serveur CAS.
...@@ -70,6 +35,28 @@ return [ ...@@ -70,6 +35,28 @@ return [
'debug' => false, 'debug' => false,
], ],
], ],
]
],
/**
* Configuration de l'authentification locale (compte LDAP établissement, ou compte BDD application).
*/
'local' => [
'order' => 2,
'enabled' => true,
'description' => "Utilisez ce formulaire si vous possédez un compte LDAP établissement ou un compte local dédié à l'application.",
/**
* Mode d'authentification à l'aide d'un compte dans la BDD de l'application.
*/
'db' => [
'enabled' => true, // doit être activé pour que l'usurpation fonctionne (cf. Authentication/Storage/Db::read()) :-/
],
/**
* Mode d'authentification à l'aide d'un compte LDAP.
*/
'ldap' => [
'enabled' => true,
], ],
], ],
...@@ -77,7 +64,7 @@ return [ ...@@ -77,7 +64,7 @@ return [
* Authentification via la fédération d'identité (Shibboleth). * Authentification via la fédération d'identité (Shibboleth).
*/ */
'shib' => [ 'shib' => [
'order' => 4, 'order' => 3,
'enabled' => false, 'enabled' => false,
'description' => 'description' =>
"Cliquez sur le bouton ci-dessous pour accéder à l'authentification via la fédération d'identité. " . "Cliquez sur le bouton ci-dessous pour accéder à l'authentification via la fédération d'identité. " .
......
...@@ -2,18 +2,25 @@ ...@@ -2,18 +2,25 @@
namespace UnicaenAuth\Authentication\Adapter; namespace UnicaenAuth\Authentication\Adapter;
use Zend\Authentication\Storage; use UnicaenAuth\Authentication\SessionIdentity;
use Zend\Authentication\Storage\StorageInterface;
use Zend\EventManager\EventInterface;
use Zend\EventManager\EventManagerInterface;
use Zend\EventManager\ListenerAggregateInterface;
use Zend\EventManager\ListenerAggregateTrait;
use ZfcUser\Authentication\Adapter\ChainableAdapter; use ZfcUser\Authentication\Adapter\ChainableAdapter;
abstract class AbstractAdapter implements ChainableAdapter abstract class AbstractAdapter implements ChainableAdapter, ListenerAggregateInterface
{ {
use ListenerAggregateTrait;
/** /**
* @var string * @var string
*/ */
protected $type; protected $type;
/** /**
* @var Storage\StorageInterface * @var StorageInterface
*/ */
protected $storage; protected $storage;
...@@ -27,29 +34,31 @@ abstract class AbstractAdapter implements ChainableAdapter ...@@ -27,29 +34,31 @@ abstract class AbstractAdapter implements ChainableAdapter
return $this; return $this;
} }
/**
* @return string
*/
public function getType(): string
{
return $this->type;
}
/** /**
* Returns the persistent storage handler * Returns the persistent storage handler
* *
* Session storage is used by default unless a different storage adapter has been set. * @return StorageInterface
*
* @return Storage\StorageInterface
*/ */
public function getStorage() public function getStorage(): StorageInterface
{ {
if (null === $this->storage) {
$this->setStorage(new Storage\Session(get_class($this)));
}
return $this->storage; return $this->storage;
} }
/** /**
* Sets the persistent storage handler * Sets the persistent storage handler
* *
* @param Storage\StorageInterface $storage * @param StorageInterface $storage
* @return AbstractAdapter Provides a fluent interface * @return self Provides a fluent interface
*/ */
public function setStorage(Storage\StorageInterface $storage) public function setStorage(StorageInterface $storage): self
{ {
$this->storage = $storage; $this->storage = $storage;
return $this; return $this;
...@@ -60,7 +69,7 @@ abstract class AbstractAdapter implements ChainableAdapter ...@@ -60,7 +69,7 @@ abstract class AbstractAdapter implements ChainableAdapter
* *
* @return bool * @return bool
*/ */
public function isSatisfied() public function isSatisfied(): bool
{ {
$storage = $this->getStorage()->read(); $storage = $this->getStorage()->read();
return (isset($storage['is_satisfied']) && true === $storage['is_satisfied']); return (isset($storage['is_satisfied']) && true === $storage['is_satisfied']);
...@@ -70,13 +79,41 @@ abstract class AbstractAdapter implements ChainableAdapter ...@@ -70,13 +79,41 @@ abstract class AbstractAdapter implements ChainableAdapter
* Set if this adapter is satisfied or not * Set if this adapter is satisfied or not
* *
* @param bool $bool * @param bool $bool
* @return AbstractAdapter * @return self
*/ */
public function setSatisfied($bool = true) public function setSatisfied($bool = true): self
{ {
$storage = $this->getStorage()->read() ?: array(); $storage = $this->getStorage()->read() ?: array();
$storage['is_satisfied'] = $bool; $storage['is_satisfied'] = $bool;
$this->getStorage()->write($storage); $this->getStorage()->write($storage);
return $this; return $this;
} }
/**
* @param string $username
* @return SessionIdentity
*/
protected function createSessionIdentity(string $username): SessionIdentity
{
return SessionIdentity::newInstance($username, $this->type);
}
/**
* Called when user id logged out
*
* @param EventInterface $e
*/
public function logout(EventInterface $e)
{
$this->getStorage()->clear();
}
/**
* @inheritDoc
*/
public function attach(EventManagerInterface $events, $priority = 1)
{
$events->attach('authenticate', [$this, 'authenticate'], $priority);