<?php
namespace App\Security;
use App\DTOs\UserMe;
use App\Entity\Monolith\User;
use App\Helper\LoginHelper;
use Doctrine\ORM\EntityManagerInterface;
use Exception;
use Psr\Log\LoggerInterface;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
use Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException;
use Symfony\Component\Security\Core\Exception\UnsupportedUserException;
use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface;
use Symfony\Component\Security\Core\User\PasswordUpgraderInterface;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\User\UserProviderInterface;
class UserProvider implements UserProviderInterface, PasswordUpgraderInterface
{
public function __construct(
private RequestStack $requestStack,
private EntityManagerInterface $entityManager,
private LoggerInterface $logger)
{
}
public function loadUserByUsername(string $username): UserInterface
{
throw new Exception('Never load by username');
}
public function loadUserByIdentifier(string $identifier): UserInterface
{
$headers = $this->requestStack->getCurrentRequest()->headers;
$kindergarten = $headers->get('X-KINDERGARTEN-ID');
$userMe = LoginHelper::fetchUser(
$this->entityManager,
'email',
$identifier,
$headers->get('user-type'),
$kindergarten
);
if (null === $userMe) {
throw new UnauthorizedHttpException('', 'Invalid credentials.');
}
if (!empty($kindergarten)) {
if (!in_array($kindergarten, $userMe->getKindergartenIds())) {
$this->logger->critical('No access: ' . $identifier . ' -> ' . $kindergarten);
throw new AccessDeniedHttpException('No access to specified kindergarten');
}
$userMe->setKindergartenIdHeader($kindergarten);
}
$userType = $headers->get('USER-TYPE');
if ($userType) {
if (!in_array($userType, User::APP_TYPES)) {
throw new AccessDeniedHttpException('Wrong USER-TYPE header');
}
$userMe->setUserTypeHeader($userType);
}
$childId = $headers->get('X-CHILD-ID');
if (User::APP_TYPE_PARENT == $userType && empty($childId)) {
// probably we need it, but we have to solve this exception when parent requests /me after login
// throw new AccessDeniedHttpException('X-CHILD-ID header missed');
}
if ($childId && !in_array($childId, $userMe->getChildrenIds())) {
throw new AccessDeniedHttpException('No access to specified child');
}
return $userMe
->setChildIdHeader($childId)
;
}
public function refreshUser(UserInterface $user): UserInterface
{
if (!$user instanceof UserMe) {
throw new UnsupportedUserException(sprintf('Invalid user class "%s".', get_class($user)));
}
return $user;
}
public function supportsClass(string $class): bool
{
return UserMe::class === $class || is_subclass_of($class, UserMe::class);
}
public function upgradePassword(PasswordAuthenticatedUserInterface $user, string $newHashedPassword): void
{
// TODO: Implement upgradePassword() method.
}
}