authenticationService = $authenticationService; } /** * Retourne l'utilisateur BDD courant * * @return UserInterface */ public function getDbUser() { if (($identity = $this->getIdentity())) { if (isset($identity['db']) && $identity['db'] instanceof UserInterface) { return $identity['db']; } } return null; } /** * Retourne l'utilisateur LDAP courant * * @return People */ public function getLdapUser() { if (($identity = $this->getIdentity())) { if (isset($identity['ldap']) && $identity['ldap'] instanceof People) { return $identity['ldap']; } } return null; } /** * Retourne l'éventuel utilisateur Shibboleth courant. * * @return ShibUser|null */ public function getShibUser() { if (($identity = $this->getIdentity())) { if (isset($identity['shib']) && $identity['shib'] instanceof ShibUser) { return $identity['shib']; } } return null; } /** * Retourne les données d'identité correspondant à l'utilisateur courant. * * @return mixed */ public function getIdentity() { if (null === $this->identity) { if ($this->authenticationService->hasIdentity()) { $this->identity = $this->authenticationService->getIdentity(); } } return $this->identity; } /** * Retourne l'identifiant de connexion de l'utilisateur courant. * * @return string|null */ public function getIdentityUsername() { if ($user = $this->getShibUser()) { return $user->getUsername(); } if ($user = $this->getLdapUser()) { return $user->getUsername(); } if ($user = $this->getDbUser()) { return $user->getUsername(); } return null; } /** * Retourne le type de l'authentification effectuée. * * @return string */ public function getAuthenticationType(): string { $identityArray = $this->getIdentity(); return Auth::extractTypeFromIdentityArray($identityArray); } /** * @param string $roleId * * @return Role */ public function getIdentityRole($roleId) { $roles = $this->getServiceAuthorize()->getRoles(); if (isset($roles[$roleId])) { return $roles[$roleId]; } return null; } /** * Retourne tous les rôles de l'utilisateur courant, pas seulement le rôle courant sélectionné. * * Les clés du tableau sont les ID de rôles, les valeurs sont les objets Role * * @return Role[] */ public function getIdentityRoles() { if (null === $this->identityRoles) { $this->identityRoles = []; $roles = $this->getServiceAuthorize()->getRoles(); $identityProvider = $this->getIdentityProvider(); if ($identityProvider instanceof Chain) { $identityRoles = $identityProvider->getAllIdentityRoles(); } else { $identityRoles = $identityProvider->getIdentityRoles(); } foreach ($identityRoles as $role) { if ($role instanceof RoleInterface) { $this->identityRoles[$role->getRoleId()] = $role; } elseif (is_string($role) && isset($roles[$role])) { $role = $roles[$role]; /** @var RoleInterface $role */ $this->identityRoles[$role->getRoleId()] = $role; } } } return $this->identityRoles; } public function clearIdentityRoles() { $this->identityRoles = null; } /** * Retourne tous les rôles de l'utilisateur courant au format littéral. * * @return array * @see getIdentityRoles() */ public function getIdentityRolesToString() { $f = new RoleFormatter(); $rolesToStrings = []; foreach ($this->getIdentityRoles() as $identityRole) { $rolesToStrings[$identityRole->getRoleId()] = $f->format($identityRole); } return $rolesToStrings; } /** * Retourne parmi tous les rôles de l'utilisateur courant ceux qui peuvent être sélectionnés. * * NB: si plus d'un rôle sont sélectionnables, on zappe le rôle "Authentifié". * * @return array */ public function getSelectableIdentityRoles() { $filter = function ($r) { return !($r instanceof NamedRole && !$r->getSelectable()); }; $roles = array_filter($this->getIdentityRoles(), $filter); // si plus d'un rôle sont sélectionnables, on zappe le rôle "Authentifié" if (count($roles) > 1 && isset($roles['user'])) { unset($roles['user']); } return $roles; } /** * Si un utilisateur est authentifié, retourne le rôle utilisateur sélectionné, * ou alors le premier sélectionnable si aucun n'a été sélectionné. * * @return RoleInterface|null */ public function getSelectedIdentityRole() { // Si aucun utilisateur n'est authentifié, basta ! if (! $this->getIdentity()) { return null; } // NB: Si un rôle est spécifié en session comme devant être le prochain rôle sélectionné, // c'est lui qui est pris en compte. if ($next = $this->getNextSelectedIdentityRole()) { $this->getSessionContainer()->selectedIdentityRole = $next; // écriture en session } // Si en session aucun rôle n'est sélectionné ou si cette sélection n'est pas valide, // on sélectionne le 1er rôle sélectionnable. $selectedRoleId = $this->getSessionContainer()->selectedIdentityRole; $selectableRoles = $this->getSelectableIdentityRoles(); if (null === $selectedRoleId || ! isset($selectableRoles[$selectedRoleId])) { $firstSelectableRoleId = reset($selectableRoles); $this->setSelectedIdentityRole($firstSelectableRoleId); // écriture en session } // Rôle sélectionné en session. $roleId = $this->getSessionContainer()->selectedIdentityRole; // lecture en session if (! $roleId) { return null; } $role = $selectableRoles[$roleId]; if (! $this->isRoleValid($role)) { return null; } return $role; } /** * Retourne le rôle utilisateur sélectionné éventuel au format littéral. * * @return string * @see getSelectedIdentityRole() */ public function getSelectedIdentityRoleToString() { $role = $this->getSelectedIdentityRole(); if (! $role) { return null; } $f = new RoleFormatter(); return $f->format($role); } /** * Mémorise en session le rôle spécifié comme étant le rôle courant de l'utilisateur. * * NB: seul l'id du rôle est mémorisé en session. * * @param RoleInterface|string $role * * @return \UnicaenAuth\Service\UserContext * @throws RuntimeException */ public function setSelectedIdentityRole($role) { if ($role) { if (!$this->isRoleValid($role)) { throw new RuntimeException("Rôle spécifié invalide."); } if ($role instanceof RoleInterface) { $role = $role->getRoleId(); } $this->getSessionContainer()->selectedIdentityRole = $role; } else { unset($this->getSessionContainer()->selectedIdentityRole); } $role = $this->getSelectableIdentityRoles()[$role]; if ($role instanceof AbstractRole) { $this->saveUserLastRole($role); } $this->triggerUserRoleSelectedEvent(UserRoleSelectedEvent::POST_SELECTION, $role); return $this; } /** * @param AbstractRole $role */ private function saveUserLastRole(AbstractRole $role) { /** @var AbstractUser $user */ $user = $this->getDbUser(); if (! $user) { return; } $user->setLastRole($role); try { $this->getEntityManager()->flush($user); } catch (ORMException $e) { throw new RuntimeException("Erreur rencontrée lors de l'enregistrement en bdd", null, $e); } } /** * Retourne l'éventuel rôle spécifié en session devant être le prochain rôle sélectionné. * * @return string|null */ public function getNextSelectedIdentityRole() { return $this->getSessionContainer()->nextSelectedIdentityRole; } /** * Mémorise en session le rôle devant être le prochain rôle sélectionné. * * NB: seul l'id du rôle est mémorisé en session ; la durée de vie du stockage est de 1 requête seulement. * * @param RoleInterface|string $role Le ROLE_ID du rôle (string) ou une instance (RoleInterface) * * @return \UnicaenAuth\Service\UserContext */ public function setNextSelectedIdentityRole($role) { if ($role instanceof RoleInterface) { $role = $role->getRoleId(); } if ($role) { $this->getSessionContainer()->nextSelectedIdentityRole = $role; $this->getSessionContainer()->setExpirationHops(1, 'nextSelectedIdentityRole'); } else { unset($this->getSessionContainer()->nextSelectedIdentityRole); } $role = $this->getSelectableIdentityRoles()[$role] ?? null; if ($role instanceof AbstractRole) { $this->saveUserLastRole($role); } if ($role) { $this->triggerUserRoleSelectedEvent(UserRoleSelectedEvent::POST_SELECTION, $role); } return $this; } /** * Déclenche l'événement donnant à l'application l'opportunité de réagir à la sélection d'un rôle. * * @param string $name Ex: UserRoleSelectedEvent::POST_SELECTION * @param RoleInterface|string|null $role Rôle sélectionné */ private function triggerUserRoleSelectedEvent($name, $role) { $event = new UserRoleSelectedEvent($name); $event ->setRole($role) ->setTarget($this); $this->getEventManager()->triggerEvent($event); } /** * Teste si le rôle spécifié fait partie des rôles disponibles. * * @param RoleInterface|string $role * * @return boolean */ public function isRoleValid($role) { if ($role instanceof RoleInterface) { $role = $role->getRoleId(); } foreach ($this->getIdentityRoles() as $r) { if ($r instanceof RoleInterface) { $r = $r->getRoleId(); } if ($role === $r) { return true; } } return false; } /** * * @return Chain */ private function getIdentityProvider() { /* @var $identityProvider Chain */ $identityProvider = $this->getServiceAuthorize()->getIdentityProvider(); return $identityProvider; } /** * Détermine si une usurpation d'identité est en cours. * * @return bool */ public function isUsurpationEnCours(): bool { /** @var array $currentIdentity */ $currentIdentity = $this->getIdentity(); return isset($currentIdentity['usurpation']); } /** * Usurpe l'identité d'un autre utilisateur. * @param string $usernameUsurpe * @return SessionIdentity|null */ public function usurperIdentite(string $usernameUsurpe): ?SessionIdentity { /** @var array $currentIdentityArray */ $currentIdentityArray = $this->getIdentity(); $identity = null; if ($identity === null && isset($currentIdentityArray['db'])) { /** @var AbstractUser $identity */ $identity = $currentIdentityArray['db']; } if ($identity === null && isset($currentIdentityArray['ldap'])) { /** @var People $identity */ $identity = $currentIdentityArray['ldap']; } if ($identity === null && isset($currentIdentityArray['shib'])) { /** @var ShibUser $identity */ $identity = $currentIdentityArray['shib']; } if ($identity === null) { return null; } // seuls les logins spécifiés dans la config sont habilités à usurper des identités if (! in_array($identity->getUsername(), $this->moduleOptions->getUsurpationAllowedUsernames())) { throw new RuntimeException("Usurpation non explicitement autorisée"); } $usernameUsurpateur = $identity->getUsername(); $sessionIdentity = SessionIdentity::newInstanceForUsurpation($usernameUsurpe, $usernameUsurpateur, $this->getAuthenticationType()); $this->authenticationService->getStorage()->write($sessionIdentity); return $sessionIdentity; } /** * Met fin à l'usurpation d'identité en cours. */ public function stopperUsurpation() { if (! $this->isUsurpationEnCours()) { return; } /** @var array $currentIdentityArray */ $currentIdentityArray = $this->getIdentity(); /** @var AbstractUser $usurpateur */ $usurpateur = Usurpation::extractUsurpateurFromIdentityArray($currentIdentityArray); $sessionIdentity = SessionIdentity::newInstance($usurpateur->getUsername(), $this->getAuthenticationType()); $this->authenticationService->getStorage()->write($sessionIdentity); // Sélection du dernier rôle endossé. if ($role = $usurpateur->getLastRole()) { $this->setNextSelectedIdentityRole($role); } } }