[ '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); } }