<?php
namespace App\Security\Authentication\Provider;
use App\Exception\Security\InvalidAccessTokenException;
use App\Security\Authentication\Token\OAuthToken;
use App\Service\Security\AuthServer;
use Aqarmap\Bundle\UserBundle\Entity\User;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\Security\Core\Authentication\Provider\AuthenticationProviderInterface;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Core\User\UserProviderInterface;
class OAuthProvider implements AuthenticationProviderInterface
{
private AuthServer $authServer;
private EntityManagerInterface $entityManager;
public function __construct(UserProviderInterface $userProvider, AuthServer $authServer, EntityManagerInterface $entityManager)
{
$this->authServer = $authServer;
$this->entityManager = $entityManager;
}
/**
* @throws InvalidAccessTokenException
*/
public function authenticate(TokenInterface $token): ?TokenInterface
{
if (!$this->supports($token)) {
return null;
}
try {
$tokenInfo = $this->authServer->getTokenInfo($token->getToken());
if (!$tokenInfo['oauth_client_id'] ?? null) {
throw new AuthenticationException('OAuth2 authentication failed. Client identifier not found.');
}
$oauthRoles = $tokenInfo['roles'] ?? [];
$authenticateToken = new OAuthToken($tokenInfo['roles'] ?? []);
if ($authUerIdentifier = $tokenInfo['user']['id'] ?? null) {
$userRepo = $this->entityManager->getRepository(User::class);
if ($user = $userRepo->findOneBy(['authIdentifier' => $authUerIdentifier])) {
$authenticateToken = new OAuthToken(array_merge($oauthRoles, $user->getRoles()));
$authenticateToken->setUser($user);
} elseif ($user = $userRepo->findOneBy(['emailCanonical' => $tokenInfo['user']['email'] ?? null])) {
$authenticateToken = new OAuthToken(array_merge($oauthRoles, $user->getRoles()));
$authenticateToken->setUser($user);
} else {
// @todo: Signup the user if doesn't exists?
throw new AuthenticationException(sprintf('Could not find user profile with identifier "%s".', $authUerIdentifier));
}
}
$authenticateToken->setAuthenticated(true);
$authenticateToken->setToken($token->getToken());
return $authenticateToken;
} catch (InvalidAccessTokenException $exception) {
throw $exception;
} catch (\Exception $exception) {
throw new AuthenticationException(sprintf('OAuth2 authentication failed. (%s)', $exception->getMessage()), 0, $exception);
}
}
public function supports(TokenInterface $token): bool
{
return $token instanceof OAuthToken;
}
}