<?php
namespace App\Security;
use Empire\Core\User;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\DBAL\FetchMode;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
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\Http\Authenticator\AbstractAuthenticator;
use Symfony\Component\Security\Core\Exception\CustomUserMessageAuthenticationException;
use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge;
use Symfony\Component\Security\Http\Authenticator\Passport\Badge\PreAuthenticatedUserBadge;
use Symfony\Component\Security\Http\Authenticator\Passport\Passport;
use Symfony\Component\Security\Http\Authenticator\Passport\SelfValidatingPassport;
use Symfony\Component\Security\Http\Authenticator\Passport\Credentials\CustomCredentials;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\RequestStack;
use App\Security\UserProvider;
use Empire\Core\Core;
class EmpireAuthenticator extends AbstractAuthenticator
{
private $entityManager;
private $requestStack;
private $userProvider;
public function __construct(EntityManagerInterface $entityManager, RequestStack $requestStack, UserProvider $userProvider)
{
$this->entityManager = $entityManager;
$this->requestStack = $requestStack;
$this->userProvider = $userProvider;
}
/**
* 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
{
$cook = false;
if ($request->cookies->has('irms_token')){
$tok = $request->cookies->get('irms_token');
if ($tok != '' || !is_null($tok)) {
$cook = true;
}
}
return $cook || $this->requestStack->getSession()->has('member_id');
}
public function getCredentials(Request $request)
{
if ($request->cookies->has('irms_token')){
list($token, $signature) = explode(":", $request->cookies->get('irms_token'), 2);
if ($signature != hash_hmac('md5', $token, $_ENV['APP_SECRET'])) {
throw new \Exception('Invalid cookie!');
}
return $token;
}
return "_no_cookie"; // special val, to show no cookie usage and to check session
}
public function getUser($credentials, UserProviderInterface $userProvider)
{
if (null === $credentials) {
// The token header was empty, authentication fails with HTTP Status
// Code 401 "Unauthorized"
return null;
}
if ($credentials == "_no_cookie"){
$membid = $this->requestStack->getSession()->get('member_id');
return $userProvider->loadUserByUsername($membid);
}
// no session, so a remember_me
return $userProvider->loadUserByIrmsToken($credentials);
}
public function checkCredentials($credentials, UserInterface $user)
{
return true;
}
public function authenticate(Request $request): Passport
{
$cookie = $request->cookies->get('irms_token');
if (is_null($cookie)){
$membid = $this->requestStack->getSession()->get('member_id');
if(is_null($membid)){
throw new CustomUserMessageAuthenticationException('No token provided');
}
return new SelfValidatingPassport(new UserBadge($this->userProvider->loadUserByUsername($membid)), [new PreAuthenticatedUserBadge()]);
} else {
list($token, $signature) = explode(":", $cookie, 2);
if ($signature != hash_hmac('md5', $token, $_ENV['APP_SECRET'])) {
throw new \Exception('Invalid cookie!');
}
$conn = $this->entityManager->getConnection();
$sql = "SELECT MEMB_ID FROM COOKIE WHERE COOK_TOKEN = '$token';";
$stmt = $conn->prepare($sql);
$stmt->execute();
$return = $stmt->fetch();
$id = $return["MEMB_ID"];
$usql = "SELECT * FROM MEMBER WHERE MEMB_ID = '$id';";
$ust = $conn->prepare($usql);
$ust->setFetchMode(\PDO::FETCH_CLASS, \Empire\Core\User::class);
$ust->execute();
$user = $ust->fetch();
if (is_null($user)) {
throw new UserNotFoundException();
}
return new SelfValidatingPassport(new UserBadge($user));
}
}
public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $firewallName): ?Response
{
// on success, let the request continue
return null;
}
public function onAuthenticationFailure(Request $request, AuthenticationException $exception): ?Response
{
$data = [
// you may want to customize or obfuscate the message first
'message' => strtr($exception->getMessageKey(), $exception->getMessageData())
// or to translate this message
// $this->translator->trans($exception->getMessageKey(), $exception->getMessageData())
];
return new JsonResponse($data, Response::HTTP_UNAUTHORIZED);
}
/**
* Called when authentication is needed, but it's not sent
*/
public function start(Request $request, AuthenticationException $authException = null)
{
// send to login
//var_dump($request->server->all());
$reqUri = urlencode($request->server->get('REQUEST_URI'));
return new RedirectResponse("/login?returnUrl={$reqUri}&client=Forum");
}
public function supportsRememberMe()
{
return true;
}
}