src/CoreBundle/EventSubscriber/AnonymousUserSubscriber.php line 89

  1. <?php
  2. /* For licensing terms, see /license.txt */
  3. declare(strict_types=1);
  4. namespace Chamilo\CoreBundle\EventSubscriber;
  5. use Chamilo\CoreBundle\Entity\TrackELogin;
  6. use Chamilo\CoreBundle\Entity\User;
  7. use Chamilo\CoreBundle\Settings\SettingsManager;
  8. use DateTime;
  9. use Doctrine\ORM\EntityManagerInterface;
  10. use Symfony\Bundle\SecurityBundle\Security;
  11. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  12. use Symfony\Component\HttpKernel\Event\RequestEvent;
  13. use Symfony\Component\HttpKernel\KernelEvents;
  14. class AnonymousUserSubscriber implements EventSubscriberInterface
  15. {
  16.     private const MAX_ANONYMOUS_USERS 5;
  17.     public function __construct(
  18.         private readonly Security $security,
  19.         private readonly EntityManagerInterface $entityManager,
  20.         private readonly SettingsManager $settingsManager
  21.     ) {}
  22.     public function onKernelRequest(RequestEvent $event): void
  23.     {
  24.         if (null !== $this->security->getUser()) {
  25.             return;
  26.         }
  27.         $request $event->getRequest();
  28.         $userIp $request->getClientIp() ?: '127.0.0.1';
  29.         $anonymousUserId $this->getOrCreateAnonymousUserId($userIp);
  30.         if (null !== $anonymousUserId) {
  31.             $trackLoginRepository $this->entityManager->getRepository(TrackELogin::class);
  32.             // Check if a login record already exists for this user and IP
  33.             $existingLogin $trackLoginRepository->findOneBy(['userIp' => $userIp'user' => $anonymousUserId]);
  34.             if (!$existingLogin) {
  35.                 // Record the access if it does not exist
  36.                 $trackLogin = new TrackELogin();
  37.                 $trackLogin->setUserIp($userIp)
  38.                     ->setLoginDate(new DateTime())
  39.                     ->setUser($this->entityManager->getReference(User::class, $anonymousUserId))
  40.                 ;
  41.                 $this->entityManager->persist($trackLogin);
  42.                 $this->entityManager->flush();
  43.             }
  44.             $userRepository $this->entityManager->getRepository(User::class);
  45.             $user $userRepository->find($anonymousUserId);
  46.             if ($user) {
  47.                 // Store user information in the session
  48.                 $userInfo = [
  49.                     'user_id' => $user->getId(),
  50.                     'username' => $user->getUsername(),
  51.                     'firstname' => $user->getFirstname(),
  52.                     'lastname' => $user->getLastname(),
  53.                     'firstName' => $user->getFirstname(),
  54.                     'lastName' => $user->getLastname(),
  55.                     'email' => $user->getEmail(),
  56.                     'official_code' => $user->getOfficialCode(),
  57.                     'picture_uri' => $user->getPictureUri(),
  58.                     'status' => $user->getStatus(),
  59.                     'active' => $user->isActive(),
  60.                     'auth_source' => $user->getAuthSource(),
  61.                     'theme' => $user->getTheme(),
  62.                     'language' => $user->getLocale(),
  63.                     'registration_date' => $user->getRegistrationDate()->format('Y-m-d H:i:s'),
  64.                     'expiration_date' => $user->getExpirationDate() ? $user->getExpirationDate()->format('Y-m-d H:i:s') : null,
  65.                     'last_login' => $user->getLastLogin() ? $user->getLastLogin()->format('Y-m-d H:i:s') : null,
  66.                     'is_anonymous' => true,
  67.                 ];
  68.                 $request->getSession()->set('_user'$userInfo);
  69.             }
  70.         }
  71.     }
  72.     public static function getSubscribedEvents(): array
  73.     {
  74.         return [
  75.             KernelEvents::REQUEST => 'onKernelRequest',
  76.         ];
  77.     }
  78.     private function getOrCreateAnonymousUserId(string $userIp): ?int
  79.     {
  80.         $userRepository $this->entityManager->getRepository(User::class);
  81.         $trackLoginRepository $this->entityManager->getRepository(TrackELogin::class);
  82.         $anonymousAutoProvisioning 'true' === $this->settingsManager->getSetting('security.anonymous_autoprovisioning');
  83.         if (!$anonymousAutoProvisioning) {
  84.             $anonymousUser $userRepository->findOneBy(['status' => User::ANONYMOUS], ['registrationDate' => 'ASC']);
  85.             if ($anonymousUser) {
  86.                 return $anonymousUser->getId();
  87.             }
  88.             return $this->createAnonymousUser()->getId();
  89.         }
  90.         $maxAnonymousUsers = (int) $this->settingsManager->getSetting('admin.max_anonymous_users');
  91.         if (=== $maxAnonymousUsers) {
  92.             $maxAnonymousUsers self::MAX_ANONYMOUS_USERS;
  93.         }
  94.         $anonymousUsers $userRepository->findBy(['status' => User::ANONYMOUS], ['registrationDate' => 'ASC']);
  95.         // Check in TrackELogin if there is an anonymous user with the same IP
  96.         foreach ($anonymousUsers as $user) {
  97.             $loginRecord $trackLoginRepository->findOneBy(['userIp' => $userIp'user' => $user]);
  98.             if ($loginRecord) {
  99.                 return $user->getId();
  100.             }
  101.         }
  102.         // Delete excess anonymous users
  103.         while (\count($anonymousUsers) >= $maxAnonymousUsers) {
  104.             $oldestAnonymousUser array_shift($anonymousUsers);
  105.             if ($oldestAnonymousUser) {
  106.                 error_log('Deleting oldest anonymous user: '.$oldestAnonymousUser->getId());
  107.                 $this->entityManager->remove($oldestAnonymousUser);
  108.                 $this->entityManager->flush();
  109.             }
  110.         }
  111.         return $this->createAnonymousUser()->getId();
  112.     }
  113.     private function createAnonymousUser(): User
  114.     {
  115.         $uniqueId uniqid('anon_');
  116.         $email $uniqueId.'@localhost.local';
  117.         if ('true' === $this->settingsManager->getSetting('profile.login_is_email')) {
  118.             $uniqueId $email;
  119.         }
  120.         $anonymousUser = (new User())
  121.             ->setSkipResourceNode(true)
  122.             ->setLastname('Joe')
  123.             ->setFirstname('Anonymous')
  124.             ->setUsername('anon_'.$uniqueId)
  125.             ->setStatus(User::ANONYMOUS)
  126.             ->setPlainPassword('anon')
  127.             ->setEmail($email)
  128.             ->setOfficialCode('anonymous')
  129.             ->setCreatorId(1)
  130.             ->addRole('ROLE_ANONYMOUS')
  131.         ;
  132.         $this->entityManager->persist($anonymousUser);
  133.         $this->entityManager->flush();
  134.         return $anonymousUser;
  135.     }
  136. }