Commit 942ce407 authored by Bertrand Gauthier's avatar Bertrand Gauthier
Browse files

Merge branch 'release-1.3.5'

parents cb761a71 5e8ee47f
Loading
Loading
Loading
Loading
+0 −2
Original line number Diff line number Diff line
<?php

use UnicaenAuth\Authentication\Storage\ShibSimulatorStorage;
use UnicaenAuth\Controller\AuthControllerFactory;
use UnicaenAuth\Service\ShibService;
use UnicaenAuth\Service\ShibServiceFactory;
@@ -424,7 +423,6 @@ return [
            '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\Authentication\Storage\ShibSimulatorStorage' => ShibSimulatorStorage::class,
            'UnicaenAuth\View\RedirectionStrategy'    => 'UnicaenAuth\View\RedirectionStrategy',
            'UnicaenAuth\Service\User'                => 'UnicaenAuth\Service\User',
            'UnicaenAuth\Service\CategoriePrivilege'  => 'UnicaenAuth\Service\CategoriePrivilegeService',
+0 −1
Original line number Diff line number Diff line
@@ -16,7 +16,6 @@ class ChainServiceFactory implements FactoryInterface
    private $mandatoryStorages = [
        200 => 'UnicaenAuth\Authentication\Storage\Ldap',
        100 => 'UnicaenAuth\Authentication\Storage\Db',
        76  => 'UnicaenAuth\Authentication\Storage\ShibSimulatorStorage',
        75  => 'UnicaenAuth\Authentication\Storage\Shib',
    ];

+0 −70
Original line number Diff line number Diff line
<?php

namespace UnicaenAuth\Authentication\Storage;

use UnicaenAuth\Service\ShibService;
use Zend\ServiceManager\ServiceLocatorAwareInterface;
use Zend\ServiceManager\ServiceLocatorAwareTrait;

/**
 * Storage permettant de simuler un utilisateur authentifié via Shibboleth.
 *
 * @author Unicaen
 */
class ShibSimulatorStorage implements ChainableStorage, ServiceLocatorAwareInterface
{
    use ServiceLocatorAwareTrait;

    /**
     * @var ShibService
     */
    protected $shibService;

    /**
     * @var array
     */
    protected $shibbolethOptions;

    /**
     * {@inheritdoc}
     */
    public function read(ChainEvent $e)
    {
        if (! $this->getShibService()->isShibbolethEnabled()) {
            return;
        }
        if (! $this->getShibService()->isSimulationActive()) {
            return;
        }

        $this->getShibService()->handleSimulation();
    }

    /**
     * {@inheritdoc}
     */
    public function write(ChainEvent $e)
    {
        // nop
    }

    /**
     * {@inheritdoc}
     */
    public function clear(ChainEvent $e)
    {
        // nop
    }

    /**
     * @return ShibService
     */
    private function getShibService()
    {
        if ($this->shibService === null) {
            $this->shibService = $this->serviceLocator->get(ShibService::class);
        }

        return $this->shibService;
    }
}
 No newline at end of file
+1 −8
Original line number Diff line number Diff line
@@ -55,19 +55,12 @@ class AuthController extends AbstractActionController

        $redirectUrl = $this->params()->fromQuery('redirect', '/');

        // enclenchement de la simulation shibboleth éventuellement activée dans la config
        if ($simulate = $this->shibService->getShibbolethSimulate()) {
            $this->setStoredAuthenticatedUsername($simulate['eppn']); // tout simplement!

            return $this->redirect()->toUrl($redirectUrl);
        }

        $shibUser = $this->shibService->getAuthenticatedUser();
        if ($shibUser === null) {
            return []; // une page d'aide s'affichera si les données issues de Shibboleth attendues sont absentes
        }

        // arrivé ici, l'authentification shibboleth a été faite en bonne et due forme et a réussie.
        // arrivé ici, l'authentification shibboleth a été faite (réellement ou simulée) et a réussie.

        $this->setStoredAuthenticatedUsername($shibUser->getUsername());
        $this->userService->userAuthenticated($shibUser);
+61 −32
Original line number Diff line number Diff line
@@ -2,9 +2,9 @@

namespace UnicaenAuth\Service;

use InvalidArgumentException;
use Assert\Assertion;
use Assert\AssertionFailedException;
use InvalidArgumentException;
use UnicaenApp\Exception\LogicException;
use UnicaenApp\Exception\RuntimeException;
use UnicaenAuth\Entity\Shibboleth\ShibUser;
@@ -79,11 +79,12 @@ EOS;
        }

        if ($this->authenticatedUser === null) {
            // gestion de l'usurpation éventuelle

            // activation éventuelle de l'usurpation
            $this->handleUsurpation();
            if (! $this->getServerArrayVariable('eppn')) {
                return null;
            }

            // activation éventuelle de la simulation
            $this->handleSimulation();

            $this->authenticatedUser = $this->createShibUserFromServerArrayData();
        }
@@ -175,44 +176,51 @@ EOS;
    }

    /**
     * @return ShibUser|null
     *
     */
    public function handleSimulation()
    {
        if (! $this->isSimulationActive()) {
            return null;
            return;
        }

        // si nécessaire
        $this->handleUsurpation();

        $simulate = $this->getShibbolethSimulate();

        try {
            Assertion::keyIsset($simulate, 'eppn',
                "Clé 'eppn' introuvable ou sans valeur dans l'option 'unicaen-auth.shibboleth.simulate'");
            Assertion::contains($simulate['eppn'], '@',
                "L'eppn '" . $simulate['eppn'] . "' n'est pas de la forme 'id@domaine' attendue (ex: 'tartempion@unicaen.fr')");
            Assertion::eq(count(array_intersect($keys = ['supannEmpId', 'supannEtuId'], array_keys($simulate))), 1,
                "L'une ou l'autre de ces clés doit être présente dans l'option 'unicaen-auth.shibboleth.simulate': " .
                implode(', ', $keys));
            $shibUser = $this->createShibUserFromSimulationData();
        } catch (AssertionFailedException $e) {
            throw new LogicException("Configuration erronée", null, $e);
        }

        $eppn = $simulate['eppn'];
        $supannId = $simulate['supannEmpId'] ?: $simulate['supannEtuId'];
        $email = isset($simulate['email']) ? $simulate['email'] : null;
        $this->simulateAuthenticatedUser($shibUser);
    }

    /**
     * @return ShibUser
     * @throws AssertionFailedException
     */
    private function createShibUserFromSimulationData()
    {
        $data = $this->getShibbolethSimulate();

        $this->assertRequiredAttributesExistInData($data);

        $eppn = $this->getValueFromShibData('eppn', $data);
        $supannId = $this->getValueFromShibData('supannEmpId', $data) ?: $this->getValueFromShibData('supannEtuId', $data);
        $email = $this->getValueFromShibData('mail', $data);
        $displayName = $this->getValueFromShibData('displayName', $data);
        $givenName = $this->getValueFromShibData('givenName', $data);
        $surname = $this->getValueFromShibData('sn', $data);
        $civilite = $this->getValueFromShibData('supannCivilite', $data);

        Assertion::contains($eppn, '@', "L'eppn '" . $eppn . "' n'est pas de la forme 'id@domaine' attendue (ex: 'tartempion@unicaen.fr')");

        $shibUser = new ShibUser();
        $shibUser->setEppn($eppn);
        $shibUser->setId($supannId);
        $shibUser->setDisplayName("$eppn ($supannId)");
        $shibUser->setDisplayName($displayName);
        $shibUser->setEmail($email);
        $shibUser->setNom('Shibboleth');
        $shibUser->setPrenom('Simulation');

        $this->simulateAuthenticatedUser($shibUser);
        $shibUser->setNom($surname);
        $shibUser->setPrenom($givenName);
        $shibUser->setCivilite($civilite);

        return $shibUser;
    }
@@ -344,10 +352,14 @@ EOS;
     */
    public function simulateAuthenticatedUser(ShibUser $shibUser, $keyForId = 'supannEmpId')
    {
        // on s'assure que tous les attributs obligatoires ont une valeur
        foreach ($this->getShibbolethRequiredAttributes() as $attribute) {
            $this->setServerArrayVariable($attribute, 'qqchose');
        }
//        // on s'assure que tous les attributs obligatoires ont une valeur
//        foreach ($this->getShibbolethRequiredAttributes() as $requiredAttribute) {
//            // un pipe permet d'exprimer un OU logique, ex: 'supannEmpId|supannEtuId'
//            $attributes = array_map('trim', explode('|', $requiredAttribute));
//            foreach ($attributes as $attribute) {
//                $this->setServerArrayVariable($attribute, 'qqchose');
//            }
//        }

        // pour certains attributs, on veut une valeur sensée!
        $this->setServerArrayVariable('eppn', $shibUser->getEppn());
@@ -356,6 +368,7 @@ EOS;
        $this->setServerArrayVariable('mail', $shibUser->getEppn());
        $this->setServerArrayVariable('sn', $shibUser->getNom());
        $this->setServerArrayVariable('givenName', $shibUser->getPrenom());
        $this->setServerArrayVariable('supannCivilite', $shibUser->getCivilite());
    }

    /**
@@ -461,6 +474,22 @@ EOS;
        ]);
    }

    /**
     * @param string $name
     * @param array  $data
     * @return string
     */
    private function getValueFromShibData($name, array $data)
    {
        $key = $this->getShibbolethAliasFor($name) ?: $name;

        if (! array_key_exists($key, $data)) {
            return null;
        }

        return $data[$key];
    }

    /**
     * @param string $name
     * @param string $value