src/Controller/SecurityController.php line 94

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