<?php
namespace App\Security;
use App\Entity\IpOk;
use App\Entity\Param;
use App\Entity\User;
use App\Entity\UserLogin;
use App\Helper\Tools;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Security;
use Symfony\Component\Security\Http\Authenticator\AbstractLoginFormAuthenticator;
use Symfony\Component\Security\Http\Authenticator\Passport\Badge\CsrfTokenBadge;
use Symfony\Component\Security\Http\Authenticator\Passport\Badge\RememberMeBadge;
use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge;
use Symfony\Component\Security\Http\Authenticator\Passport\Credentials\PasswordCredentials;
use Symfony\Component\Security\Http\Authenticator\Passport\Passport;
use Symfony\Component\Security\Http\Util\TargetPathTrait;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\Session\Flash\FlashBagInterface;
use Twig\Environment;
use Symfony\Component\Mailer\MailerInterface;
use Symfony\Component\Mailer\Exception\TransportExceptionInterface;
use Symfony\Component\Mime\Email;
use Symfony\Component\Mime\Address;
use Symfony\Component\Notifier\ChatterInterface;
use Symfony\Component\Notifier\Message\ChatMessage;
class AppCustomAuthenticator extends AbstractLoginFormAuthenticator
{
use TargetPathTrait;
public const LOGIN_ROUTE = 'app_login';
private $entityManager;
private $container;
private $flashBag;
private $twig;
private $mailer;
private $chatter;
private UrlGeneratorInterface $urlGenerator;
public function __construct(UrlGeneratorInterface $urlGenerator, FlashBagInterface $flashBag, ContainerInterface $container, EntityManagerInterface $entityManager, Environment $twig, MailerInterface $mailer, ChatterInterface $chatter)
{
$this->urlGenerator = $urlGenerator;
$this->entityManager = $entityManager;
$this->container = $container;
$this->flashBag = $flashBag;
$this->twig = $twig;
$this->mailer = $mailer;
$this->chatter = $chatter;
}
public function authenticate(Request $request): Passport
{
$email = $request->request->get('_username', '');
$em = $this->entityManager;
$smiley = '';
$secureByIp = $em->getRepository(Param::class)->findOneBy(['slug' => Param::SECURE_IP_LOGIN]);
if($secureByIp) {
$secureByIp = $secureByIp->getValue();
// check bypass
$secureByIpBypass = $em->getRepository(Param::class)->findOneBy(['slug' => Param::SECURE_IP_LOGIN_BYPASS]);
if($secureByIpBypass) {
// if bypass is at least 2 characters long
if(strlen($secureByIpBypass->getValue()) > 2) {
$smiley = ' ;)';
if(isset($_GET['bypass']) && $secureByIpBypass->getValue() == $_GET['bypass']) {
$secureByIp = false;
}
}
}
} else {
$secureByIp = true;
}
// check if IP ok
if($secureByIp && $request->request->get('_username')) {
$ipInList = $em->getRepository(IpOk::class)->findOneBy(['ip' => $_SERVER['REMOTE_ADDR'], 'valid' => 1]);
if(!$ipInList) {
$this->sendIpMail($_SERVER['REMOTE_ADDR'], $request->request->get('_username'), $smiley);
}
$ipInList->setUpdateDate(new \DateTime());
$em->persist($ipInList);
$em->flush();
}
$ip = Tools::getUserIpAddr();
$query = json_decode(file_get_contents('https://stats.kelkii.com/kelapi/v1/get-ip-infos/'.$ip.'/42ESDHSzea742QGHSqDQsfQSDFQZEfqSGQgghQTQRGgQRGQRFDQHSRG'), true);
$trackIp = 'No traking data';
if(isset($query['city'])) {
$trackIp = $query['city'].' - '. $query['regionName'].' - '. $query['country'].' - '. $query['isp'];
}
// add user login
$userLog = new UserLogin();
$userLog->setLoginDate(new \DateTime());
$userLog->setDetail('Connexion le '.date('d/m/Y à H:i:s').' - '.$trackIp.' - '.$ip);
$userLog->setUserEmail($email);
$em->persist($userLog);
$connectedUser = $em->getRepository(User::class)->findOneBy(['email' => $email ]);
if(!$connectedUser) {
$this->flashBag->add('error', 'Utilisateur inconnu !');
header('Location: /');
exit;
}
$request->getSession()->getFlashBag()->add('info', $connectedUser->getLastconnexiondata());
$connectedUser->setLastconnexiondata('Dernière connexion le '.date('d/m/Y à H:i:s').' - '.$trackIp.' - '.$ip);
$em->persist($connectedUser);
$em->flush();
$request->getSession()->set(Security::LAST_USERNAME, $email);
return new Passport(
new UserBadge($email),
new PasswordCredentials($request->request->get('_password', '')),
[
new RememberMeBadge(),
new CsrfTokenBadge('authenticate', $request->request->get('_csrf_token')),
]
);
}
public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $firewallName): ?Response
{
if ($targetPath = $this->getTargetPath($request->getSession(), $firewallName)) {
return new RedirectResponse($targetPath);
}
return new RedirectResponse($this->urlGenerator->generate('homepage'));
}
protected function getLoginUrl(Request $request): string
{
return $this->urlGenerator->generate(self::LOGIN_ROUTE);
}
protected function sendIpMail($ip, $username, $smiley) {
$query = json_decode(file_get_contents('https://stats.kelkii.com/kelapi/v1/get-ip-infos/'.$ip.'/42ESDHSzea742QGHSqDQsfQSDFQZEfqSGQgghQTQRGgQRGQRFDQHSRG'), true);
$trackIp = 'No traking data';
if(isset($query['city'])) {
$trackIp = $query['city'].' - '. $query['regionName'].' - '. $query['country'].' - '. $query['isp'];
}
$postdata = http_build_query(
[
'useragent' => $_SERVER['HTTP_USER_AGENT']
]
);
$opts = ['http' =>
[
'method' => 'POST',
'header' => 'Content-Type: application/x-www-form-urlencoded',
'content' => $postdata
]
];
$context = stream_context_create($opts);
$systemInfo = json_decode(file_get_contents('https://stats.kelkii.com/kelapi/v1/device-infos/42ESDHSzea742QGHSqDQsfQSDFQZEfqSGQgghQTQRGgQRGQRFDQHSRG', false, $context), true);
if(isset($systemInfo['os'])) {
$trackIp .= ' - '.$systemInfo['os'].' - '.$systemInfo['browser'];
}
// create new IP
$em = $this->entityManager;
$now = new \DateTime('now');
$ipok = $em->getRepository(IpOk::class)->findOneBy(['ip' => $_SERVER['REMOTE_ADDR'], 'valid' => 0]);
if(!$ipok) {
$ipok = new IpOk();
$ipok->setIp($ip);
$ipok->setSlug(Tools::generateStrongPassword(30, false, 'ld'));
} elseif ($ipok->getUpdateDate()->diff($now)->i == 0) {
$this->flashBag->add('error', 'Check mail de sécurité !'.$smiley);
header('Location: /');
exit;
}
$ipok->setUpdateDate(new \DateTime());
$ipok->setValid(0);
$ipok->setTrack($trackIp);
$em->persist($ipok);
$em->flush();
$title = "Accept IP $ip to connect to Kelkii ?";
$html = $this->twig->render(
'emails/newip.html.twig',
['ip' => $ipok, 'trackIp' => $trackIp, 'username' => $username]
);
// slack message
$urlvalidation = 'https://app.kelkii.com/login/'.$ipok->getSlug();
$message = (new ChatMessage('<@Kelkii> nouvelle connexion depuis '.$ipok->getIp().' - '.$ipok->getTrack(). ' ('.$username.') : <'.$urlvalidation.'|valider>'))
->transport('slack');
$this->chatter->send($message);
// email message
$email = (new Email())
->from(new Address('r2d2@kelkii.com', 'Kelkii Connect'))
->to(new Address('fblary@gmail.com', 'Florian'))
->subject($title)
->html($html);
try {
$this->mailer->send($email);
$this->flashBag->add('error', 'Mail de sécurité envoyé !'.$smiley);
header('Location: /');
exit;
} catch (TransportExceptionInterface $e) {
Tools::sendErrorToKelkii('Custom Auth - ' . $title, urlencode(json_encode($e->getMessage())));
echo $e->getMessage();exit;
}
}
}