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

Merge branch 'release-1.3.5'

parents cb761a71 5e8ee47f
Pipeline #3491 failed with stages
in 2 minutes and 4 seconds
<?php <?php
use UnicaenAuth\Authentication\Storage\ShibSimulatorStorage;
use UnicaenAuth\Controller\AuthControllerFactory; use UnicaenAuth\Controller\AuthControllerFactory;
use UnicaenAuth\Service\ShibService; use UnicaenAuth\Service\ShibService;
use UnicaenAuth\Service\ShibServiceFactory; use UnicaenAuth\Service\ShibServiceFactory;
...@@ -424,7 +423,6 @@ return [ ...@@ -424,7 +423,6 @@ return [
'UnicaenAuth\Authentication\Storage\Db' => 'UnicaenAuth\Authentication\Storage\Db', 'UnicaenAuth\Authentication\Storage\Db' => 'UnicaenAuth\Authentication\Storage\Db',
'UnicaenAuth\Authentication\Storage\Ldap' => 'UnicaenAuth\Authentication\Storage\Ldap', 'UnicaenAuth\Authentication\Storage\Ldap' => 'UnicaenAuth\Authentication\Storage\Ldap',
'UnicaenAuth\Authentication\Storage\Shib' => 'UnicaenAuth\Authentication\Storage\Shib', 'UnicaenAuth\Authentication\Storage\Shib' => 'UnicaenAuth\Authentication\Storage\Shib',
'UnicaenAuth\Authentication\Storage\ShibSimulatorStorage' => ShibSimulatorStorage::class,
'UnicaenAuth\View\RedirectionStrategy' => 'UnicaenAuth\View\RedirectionStrategy', 'UnicaenAuth\View\RedirectionStrategy' => 'UnicaenAuth\View\RedirectionStrategy',
'UnicaenAuth\Service\User' => 'UnicaenAuth\Service\User', 'UnicaenAuth\Service\User' => 'UnicaenAuth\Service\User',
'UnicaenAuth\Service\CategoriePrivilege' => 'UnicaenAuth\Service\CategoriePrivilegeService', 'UnicaenAuth\Service\CategoriePrivilege' => 'UnicaenAuth\Service\CategoriePrivilegeService',
......
...@@ -16,7 +16,6 @@ class ChainServiceFactory implements FactoryInterface ...@@ -16,7 +16,6 @@ class ChainServiceFactory implements FactoryInterface
private $mandatoryStorages = [ private $mandatoryStorages = [
200 => 'UnicaenAuth\Authentication\Storage\Ldap', 200 => 'UnicaenAuth\Authentication\Storage\Ldap',
100 => 'UnicaenAuth\Authentication\Storage\Db', 100 => 'UnicaenAuth\Authentication\Storage\Db',
76 => 'UnicaenAuth\Authentication\Storage\ShibSimulatorStorage',
75 => 'UnicaenAuth\Authentication\Storage\Shib', 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 ...@@ -55,19 +55,12 @@ class AuthController extends AbstractActionController
$redirectUrl = $this->params()->fromQuery('redirect', '/'); $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(); $shibUser = $this->shibService->getAuthenticatedUser();
if ($shibUser === null) { if ($shibUser === null) {
return []; // une page d'aide s'affichera si les données issues de Shibboleth attendues sont absentes 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->setStoredAuthenticatedUsername($shibUser->getUsername());
$this->userService->userAuthenticated($shibUser); $this->userService->userAuthenticated($shibUser);
......
...@@ -2,9 +2,9 @@ ...@@ -2,9 +2,9 @@
namespace UnicaenAuth\Service; namespace UnicaenAuth\Service;
use InvalidArgumentException;
use Assert\Assertion; use Assert\Assertion;
use Assert\AssertionFailedException; use Assert\AssertionFailedException;
use InvalidArgumentException;
use UnicaenApp\Exception\LogicException; use UnicaenApp\Exception\LogicException;
use UnicaenApp\Exception\RuntimeException; use UnicaenApp\Exception\RuntimeException;
use UnicaenAuth\Entity\Shibboleth\ShibUser; use UnicaenAuth\Entity\Shibboleth\ShibUser;
...@@ -79,11 +79,12 @@ EOS; ...@@ -79,11 +79,12 @@ EOS;
} }
if ($this->authenticatedUser === null) { if ($this->authenticatedUser === null) {
// gestion de l'usurpation éventuelle
// activation éventuelle de l'usurpation
$this->handleUsurpation(); $this->handleUsurpation();
if (! $this->getServerArrayVariable('eppn')) {
return null; // activation éventuelle de la simulation
} $this->handleSimulation();
$this->authenticatedUser = $this->createShibUserFromServerArrayData(); $this->authenticatedUser = $this->createShibUserFromServerArrayData();
} }
...@@ -175,48 +176,55 @@ EOS; ...@@ -175,48 +176,55 @@ EOS;
} }
/** /**
* @return ShibUser|null *
*/ */
public function handleSimulation() public function handleSimulation()
{ {
if (! $this->isSimulationActive()) { if (! $this->isSimulationActive()) {
return null; return;
} }
// si nécessaire
$this->handleUsurpation();
$simulate = $this->getShibbolethSimulate();
try { try {
Assertion::keyIsset($simulate, 'eppn', $shibUser = $this->createShibUserFromSimulationData();
"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));
} catch (AssertionFailedException $e) { } catch (AssertionFailedException $e) {
throw new LogicException("Configuration erronée", null, $e); throw new LogicException("Configuration erronée", null, $e);
} }
$eppn = $simulate['eppn']; $this->simulateAuthenticatedUser($shibUser);
$supannId = $simulate['supannEmpId'] ?: $simulate['supannEtuId']; }
$email = isset($simulate['email']) ? $simulate['email'] : null;
/**
* @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 = new ShibUser();
$shibUser->setEppn($eppn); $shibUser->setEppn($eppn);
$shibUser->setId($supannId); $shibUser->setId($supannId);
$shibUser->setDisplayName("$eppn ($supannId)"); $shibUser->setDisplayName($displayName);
$shibUser->setEmail($email); $shibUser->setEmail($email);
$shibUser->setNom('Shibboleth'); $shibUser->setNom($surname);
$shibUser->setPrenom('Simulation'); $shibUser->setPrenom($givenName);
$shibUser->setCivilite($civilite);
$this->simulateAuthenticatedUser($shibUser);
return $shibUser; return $shibUser;
} }
/** /**
* Retourne true si les données stockées en session indiquent qu'une usurpation d'identité Shibboleth est en cours. * 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; ...@@ -344,10 +352,14 @@ EOS;
*/ */
public function simulateAuthenticatedUser(ShibUser $shibUser, $keyForId = 'supannEmpId') public function simulateAuthenticatedUser(ShibUser $shibUser, $keyForId = 'supannEmpId')
{ {
// on s'assure que tous les attributs obligatoires ont une valeur // // on s'assure que tous les attributs obligatoires ont une valeur
foreach ($this->getShibbolethRequiredAttributes() as $attribute) { // foreach ($this->getShibbolethRequiredAttributes() as $requiredAttribute) {
$this->setServerArrayVariable($attribute, 'qqchose'); // // 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! // pour certains attributs, on veut une valeur sensée!
$this->setServerArrayVariable('eppn', $shibUser->getEppn()); $this->setServerArrayVariable('eppn', $shibUser->getEppn());
...@@ -356,6 +368,7 @@ EOS; ...@@ -356,6 +368,7 @@ EOS;
$this->setServerArrayVariable('mail', $shibUser->getEppn()); $this->setServerArrayVariable('mail', $shibUser->getEppn());
$this->setServerArrayVariable('sn', $shibUser->getNom()); $this->setServerArrayVariable('sn', $shibUser->getNom());
$this->setServerArrayVariable('givenName', $shibUser->getPrenom()); $this->setServerArrayVariable('givenName', $shibUser->getPrenom());
$this->setServerArrayVariable('supannCivilite', $shibUser->getCivilite());
} }
/** /**
...@@ -461,6 +474,22 @@ EOS; ...@@ -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 $name
* @param string $value * @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