<?php
namespace App\Package\Admin\Tools\EventSubscriber\LoginSubscriber;
use Symfony\Component\EventDispatcher\EventSubscriberInterface,
Symfony\Component\Security\Http\Authentication\AuthenticationUtils,
Symfony\Component\Security\Http\SecurityEvents,
Symfony\Component\Security\Http\Event\InteractiveLoginEvent,
Doctrine\ORM\EntityManagerInterface,
Symfony\Component\HttpFoundation\RequestStack;
use App\Package\Toolkit\ApplicationMode\ApplicationMode,
App\Package\Toolkit\ConfigurationBag\ConfigurationBag,
App\Package\Toolkit\AdjacentFirewallLogin\AdjacentFirewallLogin;
use App\Package\Admin\Main\EntityInterface\{ AdminInterface, LoginHistoryInterface};
use Symfony\Component\Security\Http\Event\LoginFailureEvent;
/**
* LoginSubscriber
*
* Persists login event (failed/successful) in database
*
* @author Daniel Balowski <d.balowski@openform.pl> (_creator)
* @copyright Openform
* @since 03.2019
*/
class LoginSubscriber implements EventSubscriberInterface
{
/**
* @var ApplicationMode
*/
protected $applicationMode;
/**
* @var ConfigurationBag
*/
protected $configBag;
/**
* @var EntityManagerInterface
*/
protected $em;
/**
* @var AuthenticationUtils
*/
protected $authUtils;
/**
* @var AdjacentFirewallLogin
*/
protected $adjacentFirewallLogin;
/**
* @param ApplicationMode $applicationMode
* @param ConfigurationBag $configBag
* @param EntityManagerInterface $em
* @param RequestStack $requestStack
* @param AuthenticationUtils $authUtils
*/
public function __construct(
ApplicationMode $applicationMode,
ConfigurationBag $configBag,
EntityManagerInterface $em,
RequestStack $requestStack,
AuthenticationUtils $authUtils
) {
$this->applicationMode = $applicationMode;
$this->configBag = $configBag;
$this->em = $em;
$this->authUtils = $authUtils;
$this->adjacentFirewallLogin = new AdjacentFirewallLogin(
$requestStack->getMainRequest()
);
}
/**
* @return array
*/
public static function getSubscribedEvents() : array
{
return [
SecurityEvents::INTERACTIVE_LOGIN => [
[ 'onSecurityInteractiveLogin', 10 ],
],
LoginFailureEvent::class => [
[ 'onAuthenticationFailure', 10 ]
]
];
}
/**
* On successful login
*
* @param InteractiveLoginEvent $event
*
* @return void
*/
public function onSecurityInteractiveLogin(InteractiveLoginEvent $event) : void
{
if ($this->applicationMode->getCurrentMode() !== 'admin') {
return;
}
/** @var \App\Package\Admin\Main\Entity\Admin */
$admin = $event->getAuthenticationToken()->getUser();
$this->adjacentFirewallLogin->setAdjacentToken($event);
$this->persistLoginHistory(true, $admin);
if ($admin) {
$admin->setLastSeen(new \DateTime());
$this->em->persist($admin);
$this->em->flush();
}
return;
}
/**
* On failed login
*
* @param LoginFailureEvent $event
*
* @return void
*/
public function onAuthenticationFailure(LoginFailureEvent $event) : void
{
if ($this->applicationMode->getCurrentMode() !== 'admin') {
return;
}
$this->persistLoginHistory(false, null, $this->authUtils->getLastUsername());
return;
}
/**
* Persists login history entity
*
* @param boolean $status
* @param AdminInterface|null $admin (optional)
* @param string|null $login (optional)
*
* @return void
*/
protected function persistLoginHistory(
bool $status,
AdminInterface $admin = null,
string $login = null
) : void {
$loginHistory = $this->createLoginHistory();
$login = $admin ? $admin->getLogin() : $login;
if (! $login) {
return;
}
if (! empty($_SERVER[ 'HTTP_CLIENT_IP' ])) {
$ip = $_SERVER[ 'HTTP_CLIENT_IP' ];
} elseif (! empty($_SERVER[ 'HTTP_X_FORWARDED_FOR' ])) {
$ip = $_SERVER[ 'HTTP_X_FORWARDED_FOR' ];
} else {
$ip = $_SERVER[ 'REMOTE_ADDR' ];
}
$loginHistory
->setStat($status)
->setLogin($login)
->setIp($ip);
$this->em->persist($loginHistory);
$this->em->flush();
return;
}
/**
* Creates login history entity
*
* @return LoginHistoryInterface
*/
protected function createLoginHistory() : LoginHistoryInterface
{
$loginHistoryClass = $this->configBag->get('admin:entity:login_history');
return new $loginHistoryClass();
}
}