<?php
namespace App\EventSubscriber;
use App\Component\UserRole\Manager\UserRoleManager;
use App\Entity\User;
use Scheb\TwoFactorBundle\Security\TwoFactor\Event\TwoFactorAuthenticationEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\Session\SessionInterface;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Http\Event\LoginSuccessEvent;
use Symfony\Component\Security\Http\Event\SwitchUserEvent;
class LoginSubscriber implements EventSubscriberInterface
{
public function __construct(
private readonly SessionInterface $session,
private readonly UserRoleManager $userRoleManager
) {
}
public static function getSubscribedEvents(): array
{
return [
SwitchUserEvent::class => 'onSecuritySwitchUser',
LoginSuccessEvent::class => 'onLoginSuccess',
'scheb_two_factor.authentication.complete' => 'onTwoFactorAuthenticationComplete',
];
}
public function onLoginSuccess(LoginSuccessEvent $event): void
{
$this->interactiveLogin($event->getAuthenticatedToken());
}
public function onTwoFactorAuthenticationComplete(TwoFactorAuthenticationEvent $event): void
{
$this->interactiveLogin($event->getToken());
}
public function onSecuritySwitchUser(SwitchUserEvent $event): void
{
$this->setUserGroupPermissions($event->getToken());
}
/**
* calculate and assign UserRoleEntries.
*/
private function setUserGroupPermissions(TokenInterface $token): void
{
// ROLE_SUPER_ADMIN doesn't need user_role_entries
if (\in_array('ROLE_SUPER_ADMIN', $token->getRoleNames(), true)) {
return;
}
$user = $token->getUser();
if (!$user instanceof User) {
return;
}
$roles = $user->getUserRoles();
if ($roles->isEmpty() && null !== $userRole = $this->userRoleManager->getDefaultUserRole()) {
$roles = [$userRole];
}
$entries = [];
foreach ($roles as $role) {
$rolePermissions = $this->userRoleManager->getRolePermissions($role);
// if role has all permissions, skip iteration
if (!$rolePermissions) {
$token->setAttribute('user_role_entries', []);
return;
}
if (\count($entries) > 0) {
$rolePermissions = array_intersect_key($rolePermissions, $entries);
foreach (array_diff_key($entries, $rolePermissions) as $key => $val) {
unset($entries[$key]);
}
}
foreach ($rolePermissions as $classType => $permission) {
// if classType already has a mask, calculate new mask
if (\array_key_exists($classType, $entries)) {
$entries[$classType] = $entries[$classType] | $permission['mask'];
continue;
}
$entries[$classType] = $permission['mask'];
}
}
$token->setAttribute('user_role_entries', $entries);
}
private function interactiveLogin(TokenInterface $token): void
{
$this->setUserGroupPermissions($token);
/** @var User $user */
$user = $token->getUser();
if (null !== $user->getLocale()) {
$this->session->set(AdminSubscriber::ADMIN_USER_LOCALE, $user->getLocale());
}
$this->session->set('site_access', true);
}
}