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

Merge branch 'release-3.2.0'

parents 098e285b 23c62cc7
Loading
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -37,3 +37,11 @@ Première version officielle sous ZF3.
3.1.2
-----
- Aide de vue UserUsurpationHelper : ajout de la possibilité de dessiner un simple bouton.

3.2.0
-----
- Configuration de la stratégie d'extraction d'un identifiant utile parmi les données d'authentification shibboleth
  (config 'shib_user_id_extractor').
- 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.
+0 −9
Original line number Diff line number Diff line
@@ -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;
                },
            ],
        ];
    }
+114 −64
Original line number Diff line number Diff line
<?php

use UnicaenAuth\Authentication\Adapter\AdapterChainServiceFactory;
use UnicaenAuth\Authentication\Adapter\Cas;
use UnicaenAuth\Authentication\Adapter\CasAdapterFactory;
use UnicaenAuth\Authentication\Adapter\Db;
use UnicaenAuth\Authentication\Adapter\DbAdapterFactory;
use UnicaenAuth\Authentication\Adapter\Ldap;
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\Storage\Auth;
use UnicaenAuth\Authentication\Storage\AuthFactory;
use UnicaenAuth\Authentication\Storage\DbFactory;
use UnicaenAuth\Authentication\Storage\LdapFactory;
use UnicaenAuth\Authentication\Storage\ShibFactory;
use UnicaenAuth\Authentication\Storage\Usurpation;
use UnicaenAuth\Authentication\Storage\UsurpationFactory;
use UnicaenAuth\Controller\AuthControllerFactory;
use UnicaenAuth\Controller\DroitsControllerFactory;
use UnicaenAuth\Controller\UtilisateurControllerFactory;
use UnicaenAuth\Form\CasLoginForm;
use UnicaenAuth\Form\CasLoginFormFactory;
use UnicaenAuth\Form\Droits\RoleFormFactory;
use UnicaenAuth\Form\LoginFormFactory;
use UnicaenAuth\Form\LoginForm;
use UnicaenAuth\Form\ShibLoginForm;
use UnicaenAuth\Form\ShibLoginFormFactory;
use UnicaenAuth\Guard\PrivilegeControllerFactory;
@@ -59,9 +71,9 @@ use Zend\ServiceManager\Proxy\LazyServiceFactory;

$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.
         */
@@ -70,12 +82,77 @@ $settings = [
        /**
         * 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,
        ],

        /**
         * Mode d'authentification à l'aide d'un compte LDAP.
         */
        'ldap' => [
            'enabled' => true,
            'adapter' => Ldap::class,
            'form' => LoginForm::class,
        ],
    ],

    /**
         * Description facultative de ce mode d'authentification qui apparaîtra sur le formulaire de connexion.
     * 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é.",
        'adapter' => Shib::class,
        'form' => ShibLoginForm::class,

        /**
         * URL de déconnexion.
@@ -110,68 +187,33 @@ $settings = [
            'supannEtuId|supannEmpId',
        ],
        */
    ],

        /**
     * Configuration de l'authentification LDAP (compte établissement).
         * Configuration de la stratégie d'extraction d'un identifiant utile parmi les données d'authentification
         * shibboleth.
         * Ex: identifiant de l'usager au sein du référentiel établissement, transmis par l'IDP via le supannRefId.
         */
    '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',
        'shib_user_id_extractor' => [
            // domaine (ex: 'unicaen.fr') de l'EPPN (ex: hochonp@unicaen.fr')
            'unicaen.fr' => [
                [
                    // nom du 1er attribut recherché
                    'name' => 'supannRefId', // ex: '{REFERENTIEL}1234;{ISO15693}044D1AZE7A5P80'
                    // pattern éventuel pour extraire la partie intéressante
                    'preg_match_pattern' => '|\{REFERENTIEL\}(\d+)|', // ex: permet d'extraire '1234'
                ],

    /**
     * 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.",
                [
                    // nom du 2e attribut recherché
                    'name' => 'supannEmpId',
                    // pas de pattern donc valeur directement utilisable
                    'preg_match_pattern' => null,
                ],
                [
                    // nom du 3e attribut recherché
                    'name' => 'supannEtuId',
                ],

    /**
     * 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,
            ],
        ],
        ]
    ],

    /**
@@ -240,8 +282,7 @@ return [
         * Accepted values: array containing services that implement 'ZfcUser\Authentication\Adapter\ChainableAdapter'
         */
        'auth_adapters' => [
            300 => 'UnicaenAuth\Authentication\Adapter\Ldap',
            200 => 'UnicaenAuth\Authentication\Adapter\Db',
            400 => LocalAdapter::class, // délègue à Db et Ldap
            100 => 'UnicaenAuth\Authentication\Adapter\Cas',
            50 =>  'UnicaenAuth\Authentication\Adapter\Shib',
        ],
@@ -295,6 +336,8 @@ return [
                ['controller' => 'UnicaenApp\Controller\Application', 'action' => 'informatique-et-libertes', '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' => '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' => 'authenticate', 'roles' => 'guest'],
@@ -575,6 +618,7 @@ return [
    // in /var/www/sygal/module/Application/src/Application/Controller/UtilisateurController.php on line 34
    'service_manager' => [
        'aliases'            => [
            'zfcuser_login_form' => LoginForm::class,
            'Zend\Authentication\AuthenticationService' => 'zfcuser_auth_service',
            'UnicaenAuth\Privilege\PrivilegeProvider'   => 'UnicaenAuth\Service\Privilege',
            '\UnicaenAuth\Guard\PrivilegeController'    => 'UnicaenAuth\Guard\PrivilegeController',
@@ -607,6 +651,7 @@ return [
            'UnicaenAuth\Service\UserContext'          => UserContextFactory::class,
            'zfcuser_user_mapper'                      => UserMapperFactory::class,
            'MouchardCompleterAuth'        => 'UnicaenAuth\Mouchard\MouchardCompleterAuthFactory',
            LocalAdapter::class => LocalAdapterFactory::class,
            'UnicaenAuth\Authentication\Adapter\Ldap' => LdapAdapterFactory::class,
            'UnicaenAuth\Authentication\Adapter\Db'   => DbAdapterFactory::class,
            'UnicaenAuth\Authentication\Adapter\Cas'  => CasAdapterFactory::class,
@@ -614,11 +659,16 @@ return [
            'UnicaenAuth\Authentication\Storage\Db'   => DbFactory::class,
            'UnicaenAuth\Authentication\Storage\Ldap' => LdapFactory::class,
            'UnicaenAuth\Authentication\Storage\Shib' => ShibFactory::class,
            Usurpation::class => UsurpationFactory::class,
            Auth::class => AuthFactory::class,
            'UnicaenAuth\Service\User'                => UserFactory::class,
            'UnicaenAuth\Guard\PrivilegeController'   => PrivilegeControllerFactory::class,
            'UnicaenAuth\Guard\PrivilegeRoute'        => PrivilegeRouteFactory::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,
            ShibLoginForm::class => ShibLoginFormFactory::class,
            'ZfcUser\Authentication\Adapter\AdapterChain' => AdapterChainServiceFactory::class,
+54 −40
Original line number Diff line number Diff line
<?php

use UnicaenAuth\Authentication\Adapter\Shib;
use UnicaenAuth\Authentication\Adapter\Cas;
use UnicaenAuth\Authentication\Adapter\Ldap;
use UnicaenAuth\Authentication\Adapter\Db;

return [
    'unicaen-auth' => [

        /**
         * Authentification LDAP (compte établissement).
         * Configuration de l'authentification centralisée (CAS).
         */
        'ldap' => [
        'cas' => [
            /**
             * Ordre d'affichage du formulaire de connexion.
             */
@@ -23,53 +18,45 @@ return [
            'enabled' => true,

            /**
             * Type de substitution.
             * Permet de "fusionner" les types d'authentification applicative (db) et établissement (ldap) et donc leurs
             * formulaires de connexion respectifs.
             * Description facultative de ce mode d'authentification qui apparaîtra sur la page de connexion.
             */
            'type' => 'local',
            'description' => "Cliquez sur le bouton ci-dessous pour accéder à l'authentification centralisée.",

            /**
             * Description facultative de ce mode d'authentification qui apparaîtra sur le formulaire de connexion.
             * Infos de connexion au serveur CAS.
             */
            'description' => "Utilisez ce formulaire si vous possédez un compte établissement.",
            'connection' => [
                'default' => [
                    'params' => [
                        'hostname' => 'host.domain.fr',
                        'port'     => 443,
                        'version'  => "2.0",
                        'uri'      => "",
                        'debug'    => false,
                    ],
                ],
            ]
        ],

        /**
         * Authentification BDD (compte dédié à l'appli).
         * Configuration de l'authentification locale (compte LDAP établissement, ou compte BDD application).
         */
        'db' => [
        'local' => [
            'order' => 2,
            'enabled' => true,
            'type' => 'local',
            'description' => "Utilisez ce formulaire si vous possédez un compte LDAP établissement ou un compte local dédié à l'application.",

            /**
             * 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)
             * Mode d'authentification à l'aide d'un compte dans la BDD de l'application.
             */
            'description' => "Utilisez ce formulaire si vous possédez un compte local dédié à cette application.",
            'db' => [
                'enabled' => true, // doit être activé pour que l'usurpation fonctionne (cf. Authentication/Storage/Db::read()) :-/
            ],

            /**
         * Authentification centralisée (CAS).
             * Mode d'authentification à l'aide d'un compte LDAP.
             */
        'cas' => [
            'order' => 3,
            'enabled' => false,

            /**
             * Infos de connexion au serveur CAS.
             */
            'connection' => [
                'default' => [
                    'params' => [
                        'hostname' => 'host.domain.fr',
                        'port'     => 443,
                        'version'  => "2.0",
                        'uri'      => "",
                        'debug'    => false,
                    ],
                ],
            'ldap' => [
                'enabled' => true,
            ],
        ],

@@ -77,7 +64,7 @@ return [
         * Authentification via la fédération d'identité (Shibboleth).
         */
        'shib' => [
            'order' => 4,
            'order' => 3,
            'enabled' => false,
            'description' =>
                "Cliquez sur le bouton ci-dessous pour accéder à l'authentification via la fédération d'identité. " .
@@ -128,6 +115,33 @@ return [
            //    'givenName',
            //    'supannEtuId|supannEmpId',
            //],

            /**
             * Configuration de la stratégie d'extraction d'un identifiant utile parmi les données d'authentification
             * shibboleth.
             * Ex: identifiant de l'usager au sein du référentiel établissement, transmis par l'IDP via le supannRefId.
             */
            'shib_user_id_extractor' => [
                // domaine (ex: 'unicaen.fr') de l'EPPN (ex: hochonp@unicaen.fr')
                'unicaen.fr' => [
                    [
                        // nom du 1er attribut recherché
                        'name' => 'supannRefId', // ex: '{REFERENTIEL}1234;{ISO15693}044D1AZE7A5P80'
                        // pattern éventuel pour extraire la partie intéressante
                        'preg_match_pattern' => '|\{REFERENTIEL\}(\d+)|', // ex: permet d'extraire '1234'
                    ],
                    [
                        // nom du 2e attribut recherché
                        'name' => 'supannEmpId',
                        // pas de pattern donc valeur directement utilisable
                        'preg_match_pattern' => null,
                    ],
                    [
                        // nom du 3e attribut recherché
                        'name' => 'supannEtuId',
                    ],
                ],
            ],
        ],

        /**
+54 −17
Original line number Diff line number Diff line
@@ -2,18 +2,25 @@

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;

abstract class AbstractAdapter implements ChainableAdapter
abstract class AbstractAdapter implements ChainableAdapter, ListenerAggregateInterface
{
    use ListenerAggregateTrait;

    /**
     * @var string
     */
    protected $type;

    /**
     * @var Storage\StorageInterface
     * @var StorageInterface
     */
    protected $storage;

@@ -28,28 +35,30 @@ abstract class AbstractAdapter implements ChainableAdapter
    }

    /**
     * Returns the persistent storage handler
     *
     * Session storage is used by default unless a different storage adapter has been set.
     *
     * @return Storage\StorageInterface
     * @return string
     */
    public function getStorage()
    public function getType(): string
    {
        if (null === $this->storage) {
            $this->setStorage(new Storage\Session(get_class($this)));
        return $this->type;
    }

    /**
     * Returns the persistent storage handler
     *
     * @return StorageInterface
     */
    public function getStorage(): StorageInterface
    {
        return $this->storage;
    }

    /**
     * Sets the persistent storage handler
     *
     * @param  Storage\StorageInterface $storage
     * @return AbstractAdapter Provides a fluent interface
     * @param  StorageInterface $storage
     * @return self Provides a fluent interface
     */
    public function setStorage(Storage\StorageInterface $storage)
    public function setStorage(StorageInterface $storage): self
    {
        $this->storage = $storage;
        return $this;
@@ -60,7 +69,7 @@ abstract class AbstractAdapter implements ChainableAdapter
     *
     * @return bool
     */
    public function isSatisfied()
    public function isSatisfied(): bool
    {
        $storage = $this->getStorage()->read();
        return (isset($storage['is_satisfied']) && true === $storage['is_satisfied']);
@@ -70,13 +79,41 @@ abstract class AbstractAdapter implements ChainableAdapter
     * Set if this adapter is satisfied or not
     *
     * @param bool $bool
     * @return AbstractAdapter
     * @return self
     */
    public function setSatisfied($bool = true)
    public function setSatisfied($bool = true): self
    {
        $storage = $this->getStorage()->read() ?: array();
        $storage['is_satisfied'] = $bool;
        $this->getStorage()->write($storage);
        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);
        $events->attach('logout', [$this, 'logout'], $priority);
    }
}
Loading