src/Controller/SecurityController.php line 93

Open in your IDE?
  1. <?php
  2. namespace App\Controller;
  3. use App\Constants\Setting;
  4. use App\Constants\Setting as SettingConst;
  5. use App\Constants\Sso;
  6. use App\Entity\User;
  7. use App\Factory\Security\SecurityFormFactory;
  8. use App\Form\Type\LoginType;
  9. use App\Services\Common\ModuleSettingService;
  10. use App\Services\Common\SettingService;
  11. use App\Services\Common\User\WorkflowUser;
  12. use App\Services\Common\UserService;
  13. use App\Services\DTV\YamlConfig\YamlReader;
  14. use App\Services\Security\EncryptionManager;
  15. use App\Services\Security\RegisterService;
  16. use Doctrine\ORM\EntityManagerInterface;
  17. use Exception;
  18. use LogicException;
  19. use Psr\Container\ContainerExceptionInterface;
  20. use Psr\Container\NotFoundExceptionInterface;
  21. use Psr\Log\LoggerInterface;
  22. use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
  23. use Symfony\Component\HttpFoundation\RedirectResponse;
  24. use Symfony\Component\HttpFoundation\Request;
  25. use Symfony\Component\HttpFoundation\Response;
  26. use Symfony\Component\Routing\Annotation\Route;
  27. use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
  28. use Symfony\Component\Security\Http\Authentication\AuthenticationUtils;
  29. use Symfony\Component\Translation\TranslatableMessage;
  30. use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
  31. /**
  32. * Controller qui gère la sécurité
  33. */
  34. class SecurityController extends AbstractController
  35. {
  36. private YamlReader $yamlReader;
  37. private SecurityFormFactory $formFactory;
  38. private SettingService $settingService;
  39. private EntityManagerInterface $em;
  40. private RegisterService $registerService;
  41. private EncryptionManager $encryptionManager;
  42. private WorkflowUser $workflowUser;
  43. private LoggerInterface $logger;
  44. private string $env;
  45. private UserService $userService;
  46. private ModuleSettingService $moduleSettingService;
  47. public function __construct(
  48. YamlReader $yamlReader,
  49. SecurityFormFactory $formFactory,
  50. SettingService $settingService,
  51. EntityManagerInterface $em,
  52. RegisterService $registerService,
  53. EncryptionManager $encryptionManager,
  54. WorkflowUser $workflowUser,
  55. LoggerInterface $logger,
  56. string $env,
  57. UserService $userService,
  58. ModuleSettingService $moduleSettingService
  59. ) {
  60. $this->yamlReader = $yamlReader;
  61. $this->formFactory = $formFactory;
  62. $this->settingService = $settingService;
  63. $this->em = $em;
  64. $this->registerService = $registerService;
  65. $this->encryptionManager = $encryptionManager;
  66. $this->workflowUser = $workflowUser;
  67. $this->logger = $logger;
  68. $this->env = $env;
  69. $this->userService = $userService;
  70. $this->moduleSettingService = $moduleSettingService;
  71. }
  72. /**
  73. * Formulaire de connexion
  74. *
  75. * @Route("/login", name="app_login")
  76. *
  77. * @param AuthenticationUtils $authenticationUtils
  78. * @param Request $request
  79. *
  80. * @return Response
  81. *
  82. * @throws Exception
  83. * @throws TransportExceptionInterface
  84. */
  85. public function login(AuthenticationUtils $authenticationUtils, Request $request): Response
  86. {
  87. return $this->processLogin($authenticationUtils, $request);
  88. }
  89. /**
  90. * Formulaire de connexion secondaire
  91. *
  92. * @Route("/login-admin", name="app_login_admin")
  93. *
  94. * @param AuthenticationUtils $authenticationUtils
  95. * @param Request $request
  96. *
  97. * @throws Exception
  98. * @throws TransportExceptionInterface
  99. */
  100. public function loginAdmin(AuthenticationUtils $authenticationUtils, Request $request): Response
  101. {
  102. if($this->settingService->isExist(Setting::SSO_SETTINGS) && $this->moduleSettingService->isModuleActive(Sso::MODULE_NAME))
  103. {
  104. return $this->processLogin($authenticationUtils, $request, 'security/login_admin.html.twig');
  105. }
  106. throw $this->createNotFoundException();
  107. }
  108. protected function processLogin(AuthenticationUtils $authenticationUtils, Request $request, ?string $twigPath = null): Response
  109. {
  110. // On gère ici si on est sur un Portail/enfant
  111. $setting = $this->settingService->getSettingFromName(SettingConst::PORTAL_CHILDREN);
  112. $values = $setting !== NULL ? json_decode($setting->getValue(), TRUE) : [];
  113. $hasParent = !empty($values[ 'parent_url' ]);
  114. if ($hasParent)
  115. {
  116. $header = $request->headers;
  117. if ($header->has('q') || $request->query->get('q')) {
  118. $q = base64_decode($header->get('q') ?? $request->query->get('q'));
  119. try {
  120. $q = $this->encryptionManager->decrypt($q);
  121. } catch (Exception $e) {
  122. $this->addFlash('danger', 'Un problème est survenu lors de la connexion');
  123. $this->logger->error('Erreur lors du décryptage du token de connexion', ['error' => $e->getMessage()]);
  124. return $this->redirectToRoute('app_login');
  125. }
  126. $q = json_decode($q, TRUE);
  127. $user = $this->em->getRepository(User::class)->findOneByEmailOrExtension(
  128. [
  129. 'email' => $q[ 'email' ],
  130. 'extension1' => $q[ 'extension1' ],
  131. 'extension2' => $q[ 'extension2' ],
  132. ]
  133. );
  134. if ($user instanceof User)
  135. {
  136. if ($q[ 'email' ] !== $user->getEmail()) {
  137. $user
  138. ->setEmail($q[ 'email' ])
  139. ->setFirstname($q[ 'firstName' ])
  140. ->setLastname($q[ 'lastName' ])
  141. ->setRoles($q[ 'roles' ])
  142. ;
  143. $this->registerService->registerReplaceFakeUserBySellerCode(
  144. $user,
  145. $q[ 'extension1' ],
  146. TRUE
  147. );
  148. }
  149. // Gestion du cas ou le user existe en BDD (pas en fakeUser) mais ne s'est pas encore connecté à la plateforme
  150. if ($q[ 'cguAt' ] !== NULL && $user->getStatus() === 'cgu_pending') {
  151. $this->workflowUser->acceptCGU($user);
  152. $user->setCguAt(new \DateTime($q[ 'cguAt' ]));
  153. $this->em->flush();
  154. }
  155. // Créer un token de connexion
  156. $token = new UsernamePasswordToken($user, 'app', $user->getRoles());
  157. // Stocker le token dans le token storage
  158. try {
  159. $this->container->get('security.token_storage')->setToken($token);
  160. } catch (NotFoundExceptionInterface|ContainerExceptionInterface $e) {
  161. $this->addFlash('danger', 'Un problème est survenu lors de la connexion');
  162. $this->logger->error('Erreur lors de la récupération du token storage', ['error' => $e->getMessage()]);
  163. return $this->redirectToRoute('front_homepage');
  164. }
  165. } else {
  166. // on delog l'user
  167. $this->get('security.token_storage')->setToken(NULL);
  168. $this->logger->info('L\'utilisateur n\'existe pas en BDD', ['email' => $q[ 'email' ]]);
  169. $request->getSession()->invalidate();
  170. }
  171. }
  172. }
  173. // Redirige sur la home-page si l'user est connecté
  174. if ($this->getUser()) return $this->redirectToRoute('front_homepage');
  175. $user = $this->userService->initUser();
  176. $config = $this->yamlReader->getFrontSecurity();
  177. $configLogin = $config[ 'login' ];
  178. $globalRegister = $this->yamlReader->getRegister();
  179. $globalRegisterEnabled = $globalRegister[ 'enabled' ];
  180. $configRegister = $configLogin[ 'sections' ][ 'section_register' ] ?? FALSE;
  181. $hasFormRegister = FALSE;
  182. $formRegister = FALSE;
  183. if ($globalRegisterEnabled && is_array($configRegister) && $configRegister[ 'enabled' ])
  184. {
  185. // Création du formulaire d'inscription
  186. try {
  187. $formRegister = $this->formFactory->generateRegisterForm($user);
  188. $hasFormRegister = TRUE;
  189. } catch (Exception $e) {
  190. throw $this->createNotFoundException($e->getMessage());
  191. }
  192. $formRegister->handleRequest($request);
  193. if ($formRegister->isSubmitted())
  194. {
  195. // Validation spécifique du formulaire d'inscription
  196. try {
  197. $formRegister = $this->formFactory->postValidateRegisterForm($formRegister);
  198. } catch (Exception $e)
  199. {
  200. if($this->env != 'prod') throw $e;
  201. $this->addFlash(
  202. 'danger',
  203. new TranslatableMessage('impossible d\'exécuter la post validation du formulaire', [])
  204. );
  205. $this->logger->error('Erreur lors de la post validation du formulaire d\'inscription', ['error' => $e->getMessage()]);
  206. $referer = $request->headers->get('referer');
  207. return $this->redirect($referer);
  208. }
  209. if ($formRegister->isValid())
  210. {
  211. // Post traitement du formulaire d'inscription
  212. try {
  213. $response = $this->formFactory->postProcessingRegisterForm($formRegister, $user);
  214. }
  215. catch (Exception $e)
  216. {
  217. if($this->env != 'prod') throw $e;
  218. $this->addFlash(
  219. 'danger',
  220. 'impossible d\'exécuter le post traitement du formulaire'
  221. );
  222. $this->logger->error('Erreur lors du post traitement du formulaire d\'inscription', ['error' => $e->getMessage()]);
  223. $referer = $request->headers->get('referer');
  224. return $this->redirect($referer);
  225. }
  226. catch (TransportExceptionInterface $e)
  227. {
  228. if($this->env != 'prod') throw $e;
  229. $this->addFlash(
  230. 'danger',
  231. 'impossible d\'exécuter le post traitement du formulaire'
  232. );
  233. $this->logger->error('Erreur lors du post traitement du formulaire d\'inscription', ['error' => $e->getMessage()]);
  234. $referer = $request->headers->get('referer');
  235. return $this->redirect($referer);
  236. }
  237. if ($response[ 'message' ] !== NULL) {
  238. $this->addFlash('success', $response[ 'message' ]);
  239. }
  240. return $this->redirectToRoute($response[ 'route' ]);
  241. }
  242. }
  243. }
  244. $formLogin = $this->createForm(LoginType::class);
  245. // get the login error if there is one
  246. $error = $authenticationUtils->getLastAuthenticationError();
  247. // last username entered by the user
  248. $lastUsername = $authenticationUtils->getLastUsername();
  249. if(!$twigPath)
  250. {
  251. $twigPath = 'security/login.html.twig';
  252. if (isset($configLogin[ 'folder' ])
  253. && !in_array($configLogin[ 'folder' ], [FALSE, '', NULL], TRUE)
  254. ) {
  255. $twigPath = 'security/' . $configLogin[ 'folder' ] . '/login.html.twig';
  256. }
  257. }
  258. return $this->render($twigPath, [
  259. 'last_username' => $lastUsername,
  260. 'error' => $error,
  261. 'loginForm' => $formLogin->createView(),
  262. 'registrationForm' => $hasFormRegister ? $formRegister->createView() : FALSE,
  263. 'hasFormRegister' => $hasFormRegister
  264. ]);
  265. }
  266. /**
  267. * Déconnexion
  268. *
  269. * @Route("/universal_logout", name="universal_logout")
  270. *
  271. * @return RedirectResponse
  272. */
  273. public function universalLogout(): RedirectResponse
  274. {
  275. // Vérifie si SAML est activé et si l'utilisateur est un utilisateur SAML
  276. if ($_ENV['SAML_ENABLED']) {
  277. // Redirige vers la route SAML logout
  278. return $this->redirectToRoute('saml_logout');
  279. }
  280. // Sinon redirige vers le logout standard Symfony
  281. return $this->redirectToRoute('app_logout');
  282. }
  283. /**
  284. * Déconnexion
  285. *
  286. * @Route("/logout", name="app_logout")
  287. *
  288. * @return void
  289. */
  290. public function logout(): void
  291. {
  292. throw new LogicException(
  293. 'This method can be blank - it will be intercepted by the logout key on your firewall.',
  294. );
  295. }
  296. }