<?php
namespace App\Controller;
use App\Daikin\BaseBundle\Entity\Logs;
use App\Daikin\BaseBundle\Entity\User;
use App\Security\Exception\EmailNotApprovedException;
use App\Service\Security\UserCommunicationService;
use App\Service\Security\UserCredentialsService;
use DateTime;
use Doctrine\ORM\EntityManagerInterface;
use LogicException;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
use Symfony\Component\Form\Extension\Core\Type\EmailType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Security\Core\Security;
use Symfony\Component\Security\Http\Authentication\AuthenticationUtils;
use Symfony\Component\Validator\Constraints as Assert;
class SecurityController extends AbstractController
{
/**
* @Route("/login", name="app_login")
*/
public function login(Request $request, AuthenticationUtils $authenticationUtils): Response
{
if ($this->getUser()) {
return $this->redirectToRoute('homepage');
}
// if ($request->attributes->has(Security::AUTHENTICATION_ERROR)) {
// $error = $request->attributes->get(Security::AUTHENTICATION_ERROR);
// } else {
// $error = $request->getSession()->get(Security::AUTHENTICATION_ERROR);
// $request->getSession()->remove(Security::AUTHENTICATION_ERROR);
// }
$error = $authenticationUtils->getLastAuthenticationError();
$lastUsername = $authenticationUtils->getLastUsername();
$targetPathService = '';
$targetPath = $request->getSession()->get('_security.main.target_path');
if ($targetPath && strpos($targetPath, 'authedapi') !== false){
$targetPathService = $targetPath;
}
return $this->render('security/login.html.twig', [
'last_username' => $lastUsername,
'error' => $error,
'targetPathService' => $targetPathService,
'not_enabled' => ($error instanceof EmailNotApprovedException)
]);
}
/**
* @Route("/logout", name="app_logout")
*/
public function logout(): void
{
throw new LogicException('This method can be blank - it will be intercepted by the logout key on your firewall.');
}
/**
* @Route("/login_check", name="app_login_check")
*/
public function securityCheckAction(): RedirectResponse
{
return $this->redirectToRoute('app_login');
}
/**
* @Route("/login/resend-verification/{email?}", name="security_resend_verification")
* @param Request $request
* @param EntityManagerInterface $em
* @param UserCredentialsService $credentialsService
* @param UserCommunicationService $communicationService
* @param string|null $email
* @return Response
*/
public function resendVerificationCode(Request $request, EntityManagerInterface $em, UserCredentialsService $credentialsService, UserCommunicationService $communicationService, ?string $email=null): Response
{
$form = $this->createFormBuilder(null, ['attr' => ['id' => 'register_form']])
->add('email', EmailType::class, ['label' => 'E-Mail', 'required' => true, 'data' => $email])
->add('submit', SubmitType::class, ['label' => 'Submit'])
->getForm()
->handleRequest($request)
;
$success = false;
if ($form->isSubmitted() && $form->isValid()) {
$data = $form->getData();
/** @var $user ?User */
$user = $em->getRepository(User::class)->findOneBy(['email' => $data['email'], 'approved_email' => 0]);
if ($user && $user->hasRole('ROLE_ADMIN_COMPANY')) {
$plaintextPassword = $credentialsService->updatePasswordForUser($user, null);
$em->persist($user);
$em->flush($user);
$communicationService->sendVerificationMail($user, $plaintextPassword);
$this->addFlash('success', 'Verification mail has been resent.');
$success = true;
} else {
$this->addFlash('error', 'Cannot send a new verification mail for this email address. Either it is unknown, it is already enabled or it does not belong company administrator. To resend the verification link for a user account, please contact your company administrator.');
}
}
return $this->render('@DaikinBase/Forms/resendverification.html.twig', [
'form' => $form->createView(),
'success' => $success
]);
}
/**
* VerificationAction
*
* @Route("/login/verification/{email}/{codepass}", name="security_login_verification")
* @param Request $request
* @param string $email
* @param string $codepass
* @param EntityManagerInterface $em
* @return Response
*/
public function verificationAction(Request $request, string $email, string $codepass, EntityManagerInterface $em): Response
{
$message = [
'title' => 'Verification failed.',
'message' => 'We could not verify your request. Please make sure you submit the verification link completely.',
'msgType' => 'error',
'toLogin' => false,
];
if ($user = $em->getRepository(User::class)->findOneBy(['email' => $email, 'deletestatus' => 0])) {
if ($user->isEmailApproved()) {
$message = [
'title' => 'Email address already verified.',
'message' => 'You have already verified your email address earlier.',
'msgType' => 'warning',
'toLogin' => true,
];
} elseif ($codepass == $user->getVerificationCode()) {
$logs = new Logs($user->getId(), 'User', 'User approved his E-mail.');
$em->persist($logs);
$user->setApprovedEmail(1);
$em->persist($user);
$em->flush();
$message = [
'title' => 'Verification successful.',
'message' => 'Thank you. You have successfully verified your email address.',
'msgType' => 'success',
'toLogin' => true,
];
}
if ($message['toLogin']) {
$request->getSession()->set(
Security::LAST_USERNAME,
$user->getUserIdentifier()
);
$this->addFlash( $message['msgType'], $message['message']);
return $this->redirectToRoute('app_login');
}
}
return $this->render('@DaikinBase/default/messages.html.twig', $message);
}
/**
* @Route("/login/forgot_password", name="_security_login_forgot")
* @param Request $request
* @param EntityManagerInterface $em
* @param UserCommunicationService $communicationService
* @param UserCredentialsService $credentialsService
* @return Response
*/
public function forgotPassAction(Request $request, EntityManagerInterface $em, UserCommunicationService $communicationService, UserCredentialsService $credentialsService): Response
{
$form = $this->createFormBuilder()
->add('email', EmailType::class, [
'constraints' => [
new Assert\NotBlank(),
new Assert\Email(),
]
])
->getForm()
->handleRequest($request)
;
$message = '';
if ($form->isSubmitted() && $form->isValid()) {
$data = $form->getData();
$user = $em->getRepository(User::class)->findOneBy(['email' => $data['email'], 'deletestatus' => 0]);
if ($user) {
if (!$user->getApprovedEmail()) {
$credentialsService->updatePasswordForUser($user, null);
$communicationService->sendVerificationMail($user, $user->getPPassword(), $user->getPassword());
} else {
$user->setResetRequestedAt(new DateTime());
$user->setResetRequestHash(md5(uniqid() . time()));
$communicationService->sendForgotPasswordMail($user);
}
$em->persist($user);
$em->flush();
}
// Dont let attacker check for mails
$message = 'On Your mailbox was sent new password and link for Your account verification.';
}
return $this->render('@DaikinBase/Forms/forgotpassword.html.twig', [
'message' => $message,
'message_error' => false,
'form' => $form->createView(),
]);
}
/**
* @Route("/login/reset-password/{hash}", name="resetpassword")
* @param string $hash
* @param EntityManagerInterface $em
* @param UserCommunicationService $communicationService
* @param ParameterBagInterface $parameterBag
* @param UserCredentialsService $credentialsService
* @return Response
*/
public function resetPasswordAction(string $hash, EntityManagerInterface $em, UserCommunicationService $communicationService, ParameterBagInterface $parameterBag, UserCredentialsService $credentialsService): Response
{
$error = '';
$message = '';
if ($user = $em->getRepository(User::class)->findOneBy(['reset_request_hash' => $hash])) {
if ($user->getResetRequestedAt() && ( $user->getResetRequestedAt()->getTimestamp() + $parameterBag->get('password_reset_valid') * 3600 > time() )) {
$logs = new Logs($user->getId(), 'User', 'User password Recovery.');
$em->persist($logs);
$credentialsService->updatePasswordForUser($user, null);
$user->resetResetRequest();
$communicationService->sendPasswordResetMail($user);
$em->persist($user);
$em->flush();
$message = 'Password reset successful. We have sent you a new password to your email address.';
} else {
$error = 'Reset request link not valid any more.';
$user->resetResetRequest();
$em->persist($user);
$em->flush();
}
} else
$error = 'Password reset hash invalid.';
return $this->render('@DaikinBase/default/reset_password.html.twig', [
'message' => $message,
'error' => $error,
]);
}
}