Commit 5e8ee47f authored by Bertrand Gauthier's avatar Bertrand Gauthier
Browse files

Simplifications autour de la simulation d'une authentification shibboleth.

parent cb761a71
Pipeline #3488 failed with stages
in 2 minutes and 6 seconds
<?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',
......
......@@ -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',
];
......
<?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
......@@ -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);
......
......@@ -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,48 +176,55 @@ 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;
}
/**
* Retourne true si les données stockées en session indiquent qu'une usurpation d'identité Shibboleth est en cours.
*
......@@ -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
......
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