<?php
namespace App\Security;
use App\Entity\Authentication\Person;
use App\Repository\Authentication\TenantPersonTokenRepository;
use App\Service\TenantPerson\TenantPersonService;
use Psr\Cache\InvalidArgumentException;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\User\UserProviderInterface;
use Symfony\Component\Security\Guard\AbstractGuardAuthenticator;
class SparklingAuthenticator extends AbstractGuardAuthenticator
{
private $tenantPersonTokenRepository;
private $tenantPersonService;
public function __construct(
TenantPersonTokenRepository $tenantPersonTokenRepository,
TenantPersonService $tenantPersonService
) {
$this->tenantPersonTokenRepository = $tenantPersonTokenRepository;
$this->tenantPersonService = $tenantPersonService;
}
/**
* Called on every request to decide if this authenticator should be
* used for the request. Returning `false` will cause this authenticator
* to be skipped.
*/
public function supports(Request $request): bool
{
return $request->headers->has('X-AUTH-PROTOKEN');
}
/**
* Called on every request. Return whatever credentials you want to
* be passed to getUser() as $credentials.
*/
public function getCredentials(Request $request): ?string
{
return $request->headers->get('X-AUTH-PROTOKEN');
}
/**
* @param mixed $credentials
*
* @return Person|UserInterface|null
*
* @throws \Exception
* @throws InvalidArgumentException
*/
public function getUser($credentials, UserProviderInterface $userProvider)
{
if (null === $credentials) {
// The token header was empty, authentication fails with HTTP Status
// Code 401 "Unauthorized"
return null;
}
$tenantPersonToken = $this->tenantPersonTokenRepository->findOneNotExpiredByToken($credentials);
if (!$tenantPersonToken) {
return null;
}
$tenantPerson = $tenantPersonToken->getTenantPerson();
if (!$tenantPerson) {
return null;
}
$this->tenantPersonService->init($tenantPerson);
// If this returns a user, checkCredentials() is called next:
return $tenantPerson->getPerson();
}
/**
* @param mixed $credentials
*/
public function checkCredentials($credentials, UserInterface $user): bool
{
// Check credentials - e.g. make sure the password is valid.
// In case of an API token, no credential check is needed.
// Return `true` to cause authentication success
return true;
}
public function onAuthenticationFailure(Request $request, AuthenticationException $exception): ?Response
{
throw new UnauthorizedHttpException('X-AUTH-PROTOKEN realm=Procall', 'Authentication Required.');
}
/**
* @param string $providerKey
*
* @return null
*
* @throws \Exception
*/
public function onAuthenticationSuccess(Request $request, TokenInterface $token, $providerKey)
{
// on success, let the request continue
return null;
}
/**
* Called when authentication is needed, but it's not sent.
*/
public function start(Request $request, AuthenticationException $authException = null): Response
{
throw new UnauthorizedHttpException('X-AUTH-PROTOKEN realm=Procall', 'Authentication Required.');
}
public function supportsRememberMe(): bool
{
return false;
}
}