<?php
namespace App\Controller;
use App\Entity\User;
use App\Repository\UserRepository;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Ldap\Ldap;
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;
use Symfony\Component\Security\Core\Exception\InvalidCsrfTokenException;
use Symfony\Component\Security\Csrf\CsrfToken;
use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface;
use Symfony\Component\Security\Http\Authentication\AuthenticationUtils;
use Symfony\Contracts\Translation\TranslatorInterface;
class SecurityController extends AbstractController
{
public $ldap;
private $csrfTokenManager;
private $userPasswordEncoder;
private $userRepository;
public function __construct(
Ldap $ldap,
CsrfTokenManagerInterface $csrfTokenManager,
UserPasswordEncoderInterface $userPasswordEncoder,
UserRepository $userRepository
)
{
$this->ldap=$ldap;
$this->csrfTokenManager = $csrfTokenManager;
$this->userPasswordEncoder = $userPasswordEncoder;
$this->userRepository = $userRepository;
}
public function login(AuthenticationUtils $authenticationUtils, TranslatorInterface $translator): Response
{
if ('azure' === $this->getParameter('login_method')){
return $this->redirectToRoute('connect_azure_start');
}
// get the login error if there is one
$error = $authenticationUtils->getLastAuthenticationError();
// last username entered by the user
$lastUsername = $authenticationUtils->getLastUsername();
return $this->render('security/login.html.twig', [
'error' => $error,
'last_username' => $lastUsername,
'translation_domain' => 'admin',
'page_title' => $translator->trans('pages.login.page_title'),
'csrf_token_intention' => 'authenticate',
'target_path' => $this->generateUrl('dashboard'),
'username_label' => $translator->trans('pages.login.username_label'),
'password_label' => $translator->trans('pages.login.password_label'),
'sign_in_label' => $translator->trans('pages.login.sign_in_label'),
'username_parameter' => '_username',
'password_parameter' => '_password',
]);
}
public function logout()
{
if ('azure' === $this->getParameter('login_method')){
return $this->redirectToRoute('app_logout_azure');
}
throw new \LogicException('This method can be blank - it will be intercepted by the logout key on your firewall.');
}
public function checkUserExistsAPI(Request $request){
$user_exists = false;
$user_registrable = false;
$user_data = [];
// Get Credentials
$credentials = [
'username' => $request->request->get('_username'),
'csrf_token' => $request->request->get('_csrf_token'),
];
// Check if token is correct
$token = new CsrfToken('authenticate', $credentials['csrf_token']);
if (!$this->csrfTokenManager->isTokenValid($token)) {
throw new InvalidCsrfTokenException();
}
// Check if user exists id db
$user_db = $this->getDoctrine()->getManager()->getRepository(User::class)->findOneBy(['email' => $credentials['username']]);
if ($user_db) {
$user_exists = true;
$user_data=[
'name' => $user_db->getName(),
'email'=> $user_db->getEmail(),
'md5' => md5(strtolower($user_db->getEmail())),
];
}
// Check if user is registrable
if(!$user_exists){
$user = $this->clientHelper->getUsernameData($credentials);
if($user){
$user_registrable = true;
}
}
// If user doesn't exist we check if LDAP
if(!$user_exists){
$user = $this->_checkInLDAP($credentials);
if($user){
$user_attr = $user->getAttributes();
$user_exists = true;
$user_data=[
'name' => $user_attr['displayName'],
'email' => $user_attr['userPrincipalName'][0],
'md5' => md5(strtolower($user_attr['userPrincipalName'][0])),
];
}
}
$response = [
'user_exists'=>$user_exists,
'user_registrable'=>$user_registrable,
'user_data'=>$user_data
];
return new JsonResponse ($response, Response::HTTP_OK);
}
public function _checkInLDAP($credentials){
$username= $credentials['username'];
$this->ldap->bind($_ENV['SEARCH_DN'], $_ENV['SEARCH_PASSWORD']);
$query = $this->ldap->query($_ENV['DN_STRING'], '(&(sAMAccountName='.$username.'))');
$results = $query->execute();
return $results[0] ? $results[0] : false;
}
public function registerUser($token, Request $request){
$user = $this->userRepository->findOneBy(['token'=>$token]);
if(!$user){
return false;
}
$userData = $this->clientHelper->getUsernameSingleData($user->getEmail());
$form=$this->createForm(UserRegistrationType::class, $user);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
// Retrieve Data
$entityManager = $this->getDoctrine()->getManager();
$user = $form->getData();
$user->setPassword($this->userPasswordEncoder->encodePassword(
$user,
$user->getPassword()
));
$user->setToken(null);
$entityManager->persist($user);
$entityManager->flush();
return $this->redirectToRoute('dashboard');
}
return $this->render('security/register.html.twig', [
'form' => $form->createView(),
'user_data' => $userData,
'user' => $user
]);
}
public function sendVerificationEmail(Request $request){
// Get Credentials
$credentials = [
'email' => $request->request->get('_username'),
'username' => $request->request->get('_username'),
'csrf_token' => $request->request->get('_csrf_token'),
];
// Check if token is correct
$token = new CsrfToken('authenticate', $credentials['csrf_token']);
if (!$this->csrfTokenManager->isTokenValid($token)) {
throw new InvalidCsrfTokenException();
}
// Check if username is in database
$user = $this->clientHelper->getUsernameData($credentials);
if(!$user){
return false;
}
$user = $this->createUser($credentials);
$email_to=$credentials['email'];
//$email_to= 'desarrollo@vlc.auren.es';
$mailer_from = $_ENV['MAILER_FROM'];
$subject = 'Auren Sistemas Extranet- Verificación de email';
// Configure email and send it
$transport = (new \Swift_SmtpTransport($_ENV['MAIL_HOST'], $_ENV['MAIL_PORT'], 'tls' ))
->setUsername($_ENV['MAIL_USER'])
->setPassword($_ENV['MAIL_PASSWORD'])
->setStreamOptions([
'ssl' => [
'allow_self_signed' => true,
'verify_peer' => false
]
]);
$mailer = new \Swift_Mailer($transport);
$message = (new \Swift_Message($subject))
->setFrom($mailer_from)
->setTo($email_to)
->setBody(
$this->renderView(
'emails/user/validation.html.twig',
[
'user'=>$user,
]
),
'text/html'
)
;
$success = $mailer->send($message);
$response = [
'sended'=>$success,
'email'=>$email_to,
];
return new JsonResponse ($response, Response::HTTP_OK);
}
public function sendRecoverPasswordEmail(Request $request){
// Get Credentials
$credentials = [
'email' => $request->request->get('_username'),
'username' => $request->request->get('_username'),
'csrf_token' => $request->request->get('_csrf_token'),
];
// Check if token is correct
$token = new CsrfToken('authenticate', $credentials['csrf_token']);
if (!$this->csrfTokenManager->isTokenValid($token)) {
throw new InvalidCsrfTokenException();
}
// Check if username is in database
$user = $this->clientHelper->getUsernameData($credentials);
if(!$user){
$response = [
'sended'=>false,
'text'=>'No se puede recuperar la contraseña para su tipo de usuario',
];
return new JsonResponse ($response, Response::HTTP_OK);
}
$user = $this->setNewUserToken($credentials);
$email_to=$credentials['email'];
//$email_to= 'svalero@vlc.auren.es';
$mailer_from = $_ENV['MAILER_FROM'];
$subject = 'Auren Sistemas Extranet- Recuperación de contraseña';
// Configure email and send it
$transport = (new \Swift_SmtpTransport($_ENV['MAIL_HOST'], $_ENV['MAIL_PORT'], 'tls' ))
->setUsername($_ENV['MAIL_USER'])
->setPassword($_ENV['MAIL_PASSWORD'])
->setStreamOptions([
'ssl' => [
'allow_self_signed' => true,
'verify_peer' => false
]
]);
$mailer = new \Swift_Mailer($transport);
$message = (new \Swift_Message($subject))
->setFrom($mailer_from)
->setTo($email_to)
->setBody(
$this->renderView(
'emails/user/recover_password.html.twig',
[
'user'=>$user,
]
),
'text/html'
)
;
$success = $mailer->send($message);
$response = [
'sended'=>$success,
'email'=>$email_to,
];
return new JsonResponse ($response, Response::HTTP_OK);
}
public function loginRecoverPassword($token, Request $request){
$user = $this->userRepository->findOneBy(['token'=>$token]);
if(!$user){
return false;
}
$userData = $this->clientHelper->getUsernameSingleData($user->getEmail());
$form=$this->createForm(RecoverPasswordType::class, $user);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$entityManager = $this->getDoctrine()->getManager();
$user = $form->getData();
$user->setPassword($this->userPasswordEncoder->encodePassword(
$user,
$user->getPassword()
));
$user->setToken(null);
$entityManager->persist($user);
$entityManager->flush();
return $this->redirectToRoute('dashboard');
}
return $this->render('security/recover_password.html.twig', [
'form' => $form->createView(),
'user_data' => $userData,
'user' => $user
]);
}
public function createUser($credentials){
$entityManager = $this->getDoctrine()->getManager();
$token = $this->generateToken();
$userData = $this->clientHelper->getUsernameSingleData($credentials['email']);
$user = new User();
$user->setEmail($credentials['email']);
$user->setName($userData['PContacto']);
$user->setRoles(array('ROLE_USER'));
$user->setToken($token);
$user->setActive(false);
$entityManager->persist($user);
$entityManager->flush();
return $user;
}
public function setNewUserToken($credentials){
$entityManager = $this->getDoctrine()->getManager();
$token = $this->generateToken();
$user = $this->userRepository->findOneBy(['email'=>$credentials['email']]);
$user->setToken($token);
$entityManager->persist($user);
$entityManager->flush();
return $user;
}
public function generateToken()
{
return rtrim(strtr(base64_encode(random_bytes(32)), '+/', '-_'), '=');
}
}