<?php
namespace App\Handler;
use App\Entity\User;
use App\Util\EsUtil;
use App\Service\EsCache;
use App\Entity\AccessToken;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\Security\Core\Security;
use Lexik\Bundle\JWTAuthenticationBundle\Services\JWTTokenManagerInterface;
class AccessTokenHandler
{
public function __construct(
private EntityManagerInterface $_em,
private EsCache $esCache,
private Security $security,
private JWTTokenManagerInterface $jwtManager
) {
}
public function create($token, $user = null, $container = null, $prevRefreshToken = null)
{
if (!$user) {
$user = $this->security->getUser();
}
if (!$user) {
$payload = EsUtil::decodeJWTPayloadOnly($token);
$user = $this->_em->getRepository(User::class)
->findOneBy([
'email' => $payload['username'],
'client' => $payload['cid']
]);
}
if (!$user && $prevRefreshToken) {
$accessToken = $this->_em->getRepository(AccessToken::class)
->findOneBy([
'refreshToken' => $prevRefreshToken,
'isActive' => true
]);
if ($accessToken) {
$user = $accessToken->getUser();
}
}
if (!$user) {
throw new \Exception('User not found !');
}
if (!$container) {
$container = $this->esCache->getContainer();
}
$authTokenTimeout = $container->getConfiguration('authTokenTimeout', 720);
if (empty($authTokenTimeout)) {
$authTokenTimeout = 720;
}
$expireAt = new \DateTime();
$expireAt->add(new \DateInterval('PT'.$authTokenTimeout.'M'));
$expireAt->setTimezone(new \DateTimeZone('UTC'));
$authRefreshTokenTimeout = $container->getConfiguration('authRefreshTokenTimeout', 43200);
if (empty($authRefreshTokenTimeout)) {
$authRefreshTokenTimeout = 43200;
}
$rtExpireAt = new \DateTime();
$rtExpireAt->add(new \DateInterval('PT'.$authRefreshTokenTimeout.'M'));
$rtExpireAt->setTimezone(new \DateTimeZone('UTC'));
/*
$accessToken = new AccessToken();
$accessToken
->setToken($token)
->setExpireAt($expireAt)
->setRefreshToken(self::getRefreshToken($token))
->setRtExpireAt($rtExpireAt)
->setIsActive(true)
->setUser($user)
//->setContainer($container)
;
$this->_em->persist($accessToken);
$this->_em->flush();
*/
$now = new \DateTime();
$now->setTimezone(new \DateTimeZone('UTC'));
$query = "INSERT INTO access_token(`token`, `refresh_token`, `container_id`, `user_id`, `is_active`, `created_at`, `expire_at`, `rt_expire_at`) VALUES ('".$token."', '".self::getRefreshToken($token)."', '".$container->getId()."', '".$user->getId()."', 1, '".$now->format('Y-m-d H:i:s')."', '".$expireAt->format('Y-m-d H:i:s')."', '".$rtExpireAt->format('Y-m-d H:i:s')."')";
$statement = $this->_em->getConnection()->prepare($query);
$statement->execute();
}
public function makeInactive($token, $user = null, $container = null)
{
}
public function isValid($token, $container = null)
{
if (!$container) {
$container = $this->esCache->getContainer();
}
$accessToken = $this->_em->getRepository(AccessToken::class)
->findOneBy([
'token' => $token,
'container' => $container,
'isActive' => true
]);
if ($accessToken && $accessToken->getExpireAt() > new \DateTime()) {
return true;
}
return false;
}
public function getNewToken($refreshToken, $container = null)
{
if (!$container) {
$container = $this->esCache->getContainer();
}
$accessToken = $this->_em->getRepository(AccessToken::class)
->findOneBy([
'refreshToken' => $refreshToken,
'container' => $container,
'isActive' => true
]);
if ($accessToken && $accessToken->getRtExpireAt() > new \DateTime()) {
$token = $this->jwtManager->create($accessToken->getUser());
$newAccessToken = $this->_em->getRepository(AccessToken::class)
->findOneBy([
'token' => $token,
'container' => $container,
'isActive' => true,
'user' => $accessToken->getUser()
]);
if (!$newAccessToken) {
throw new \Exception('Can not generate new token !');
}
return [
'token' => $newAccessToken->getToken(),
'refresh_token' => $newAccessToken->getRefreshToken()
];
}
return false;
}
public function logoutUser($token, $user = null, $container = null)
{
if (!$user) {
$user = $this->security->getUser();
}
if (!$container) {
$container = $this->esCache->getContainer();
}
$accessToken = $this->_em->getRepository(AccessToken::class)
->findOneBy([
'token' => $token,
'user' => $user,
'container' => $container,
'isActive' => true
]);
if ($accessToken) {
$accessToken->setIsActive(false);
$this->_em->persist($accessToken);
$this->_em->flush();
return true;
}
return false;
}
public static function getRefreshToken($token)
{
$pk = \file_get_contents(__DIR__.'/../../config/jwt/public.pem');
return sha1($token.$pk);
}
}