You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
227 lines
7.2 KiB
227 lines
7.2 KiB
<?php
|
|
namespace vierbergenlars\AuthserverExpireEmailValidationBundle\EventListener;
|
|
|
|
use App\AppEvents;
|
|
use App\Event\UserCheckerEvent;
|
|
use App\Entity\User;
|
|
use Doctrine\ORM\EntityManagerInterface;
|
|
use Doctrine\ORM\EntityRepository;
|
|
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
|
use Symfony\Component\Security\Core\Exception\AccountExpiredException;
|
|
use Symfony\Component\Security\Core\AuthenticationEvents;
|
|
use Symfony\Component\Security\Core\Event\AuthenticationEvent;
|
|
use vierbergenlars\AuthserverExpireEmailValidationBundle\Entity\ExpiredUser;
|
|
use vierbergenlars\AuthserverStatsBundle\Event\StatsEvent;
|
|
use Symfony\Component\VarDumper\VarDumper;
|
|
use Psr\Log\LoggerInterface;
|
|
use App\Mail\PrimedTwigMailer;
|
|
use Symfony\Component\Security\Core\Role\SwitchUserRole;
|
|
use vierbergenlars\AuthserverExpireEmailValidationBundle\AuthserverExpireEmailValidationBundle;
|
|
use Psr\Cache\CacheItemPoolInterface;
|
|
|
|
class CheckExpiryListener implements EventSubscriberInterface
|
|
{
|
|
|
|
/**
|
|
*
|
|
* @var EntityManagerInterface
|
|
*/
|
|
private $em;
|
|
|
|
/**
|
|
* @var CacheItemPoolInterface
|
|
*/
|
|
private $cache;
|
|
|
|
/**
|
|
*
|
|
* @var LoggerInterface
|
|
*/
|
|
private $logger;
|
|
|
|
/**
|
|
*
|
|
* @var PrimedTwigMailer
|
|
*/
|
|
private $mailer;
|
|
|
|
public static function getSubscribedEvents()
|
|
{
|
|
$events = [
|
|
AuthenticationEvents::AUTHENTICATION_SUCCESS => [
|
|
'onAuthenticationSuccess'
|
|
],
|
|
StatsEvent::class => [
|
|
'getExpiryStats',
|
|
-10
|
|
]
|
|
];
|
|
if (AuthserverExpireEmailValidationBundle::hasUserCheckEvent()) {
|
|
$events[AppEvents::SECURITY_USER_CHECK_POST] = 'onUserCheck';
|
|
}
|
|
return $events;
|
|
}
|
|
|
|
public function __construct(EntityManagerInterface $em, CacheItemPoolInterface $cache , PrimedTwigMailer $mailer, LoggerInterface $logger)
|
|
{
|
|
$this->em = $em;
|
|
$this->cache = $cache;
|
|
$this->mailer = $mailer;
|
|
$this->logger = $logger;
|
|
if (!AuthserverExpireEmailValidationBundle::hasUserCheckEvent()) {
|
|
$this->logger->critical('ExpireEmailValidationBundle can not be fully activated because the ' . AppEvents::class . '::SECURITY_USER_CHECK_POST event does not exist');
|
|
}
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @return EntityRepository
|
|
*/
|
|
private function getRepository()
|
|
{
|
|
return $this->em->getRepository(ExpiredUser::class);
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @param User $user
|
|
* @return ExpiredUser|null
|
|
*/
|
|
private function getExpiredUserForUser(User $user)
|
|
{
|
|
return $this->getRepository()->findOneBy([
|
|
'user' => $user
|
|
]);
|
|
}
|
|
|
|
public function onUserCheck(UserCheckerEvent $event)
|
|
{
|
|
$user = $event->getUser();
|
|
$this->logger->debug("Checking expiry of user", [
|
|
'user' => $user
|
|
]);
|
|
if (!($user instanceof User)) {
|
|
$this->logger->debug('Not applicable to this type of user', [
|
|
'user' => $user
|
|
]);
|
|
return;
|
|
}
|
|
|
|
$cacheItem = $this->cache->getItem('check_'.$user->getId());
|
|
|
|
if($cacheItem->isHit()) {
|
|
$this->logger->debug("Not checking expiry of user because it has been checked recently", [
|
|
'user' => $user
|
|
]);
|
|
return;
|
|
}
|
|
|
|
/* @var $user User */
|
|
$expiredUser = $this->getExpiredUserForUser($user);
|
|
|
|
$this->logger->debug('Fetched user expiry record', [
|
|
'expired_user' => $expiredUser,
|
|
'is_expired' => $expiredUser ? $expiredUser->isExpired() : null
|
|
]);
|
|
|
|
if ($expiredUser !== null && $expiredUser->isExpired()) {
|
|
$emailAddresses = $user->getEmailAddresses()->toArray();
|
|
$this->logger->info('User marked as expired. Unverifying all email addresses.', [
|
|
'user' => $user,
|
|
'email_addresses' => $emailAddresses
|
|
]);
|
|
foreach ($emailAddresses as $emailAddress) {
|
|
/* @var $emailAddress \App\Entity\EmailAddress */
|
|
$emailAddress->setVerified(false);
|
|
if (!$this->mailer->sendMessage($emailAddress->getEmail(), $emailAddress)) {
|
|
$this->logger->error('Verification email could not be sent.', [
|
|
'email_address' => $emailAddress
|
|
]);
|
|
}
|
|
}
|
|
$this->em->flush();
|
|
throw new AccountExpiredException('Email address verification expired. An email has been sent to your email addresses to reactivate your account.');
|
|
}
|
|
|
|
$cacheItem->expiresAfter(24*60*60); // Expire after a day
|
|
$this->cache->save($cacheItem);
|
|
}
|
|
|
|
public function onAuthenticationSuccess(AuthenticationEvent $event)
|
|
{
|
|
|
|
$this->logger->debug("Updating last login time of user", [
|
|
'token' => $event->getAuthenticationToken(),
|
|
'user' => $event->getAuthenticationToken()
|
|
->getUser()
|
|
]);
|
|
$token = $event->getAuthenticationToken();
|
|
foreach ($token->getRoles() as $role) {
|
|
if ($role instanceof SwitchUserRole) {
|
|
$this->logger->info('Authentication success event is caused by an impersonation. Not registering a new login.', [
|
|
'role' => $role
|
|
]);
|
|
return;
|
|
}
|
|
}
|
|
$user = $token->getUser();
|
|
|
|
if (!($user instanceof User)) {
|
|
$this->logger->debug('Not applicable to this type of user', [
|
|
'user' => $user
|
|
]);
|
|
return;
|
|
}
|
|
|
|
$cacheItem = $this->cache->getItem('update_'.$user->getId());
|
|
|
|
if($cacheItem->isHit()) {
|
|
$this->logger->debug("Not updating last login time of user because it has been refreshed recently.", [
|
|
'user' => $user,
|
|
]);
|
|
return;
|
|
}
|
|
|
|
|
|
$expiredUser = $this->getExpiredUserForUser($user);
|
|
|
|
$this->logger->debug('Fetched user expiry record', [
|
|
'expired_user' => $expiredUser,
|
|
'is_expired' => $expiredUser ? $expiredUser->isExpired() : null
|
|
]);
|
|
|
|
if ($expiredUser === null) {
|
|
$this->logger->debug('No user expiry record exists. Creating a new one.');
|
|
$expiredUser = new ExpiredUser($user);
|
|
$this->em->persist($expiredUser);
|
|
}
|
|
|
|
$expiredUser->setLastLogin(new \DateTime());
|
|
|
|
$this->em->flush($expiredUser);
|
|
|
|
$cacheItem->expiresAfter(24*60*60); // Expire after a day
|
|
$this->cache->save($cacheItem);
|
|
}
|
|
|
|
public function getExpiryStats(StatsEvent $event)
|
|
{
|
|
if (!$event->isEnabled('autoexpire'))
|
|
return;
|
|
|
|
$event->setMuninConfig('user', $event->getMuninConfig('user') + [
|
|
'autoexpire.label' => 'Expired users',
|
|
'autoexpire.draw' => 'LINE'
|
|
]);
|
|
|
|
$expiredUsers = $this->getRepository()
|
|
->createQueryBuilder('e')
|
|
->select('count(e.expiredAt)')
|
|
->where('e.expiredAt IS NOT NULL AND e.expiredAt < :now')
|
|
->setParameter('now', new \DateTime())
|
|
->getQuery()
|
|
->getSingleScalarResult();
|
|
|
|
$event->addStatistic('user.autoexpire', $expiredUsers);
|
|
}
|
|
} |