<?php
declare(strict_types=1);
namespace PhpList\RestBundle\Controller;
use FOS\RestBundle\Controller\FOSRestController;
use FOS\RestBundle\Routing\ClassResourceInterface;
use FOS\RestBundle\View\View;
use PhpList\Core\Domain\Model\Identity\Administrator;
use PhpList\Core\Domain\Model\Identity\AdministratorToken;
use PhpList\Core\Domain\Repository\Identity\AdministratorRepository;
use PhpList\Core\Domain\Repository\Identity\AdministratorTokenRepository;
use PhpList\Core\Security\Authentication;
use PhpList\RestBundle\Controller\Traits\AuthenticationTrait;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
use Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException;
/**
* This controller provides methods to create and destroy REST API sessions.
*
* @author Oliver Klee <oliver@phplist.com>
*/
class SessionController extends FOSRestController implements ClassResourceInterface
{
use AuthenticationTrait;
/**
* @var AdministratorRepository
*/
private $administratorRepository = null;
/**
* @var AdministratorTokenRepository
*/
private $tokenRepository = null;
/**
* @param Authentication $authentication
* @param AdministratorRepository $administratorRepository
* @param AdministratorTokenRepository $tokenRepository
*/
public function __construct(
Authentication $authentication,
AdministratorRepository $administratorRepository,
AdministratorTokenRepository $tokenRepository
) {
$this->authentication = $authentication;
$this->administratorRepository = $administratorRepository;
$this->tokenRepository = $tokenRepository;
}
/**
* Creates a new session (if the provided credentials are valid).
*
* @param Request $request
*
* @return View
*
* @throws UnauthorizedHttpException
*/
public function postAction(Request $request): View
{
$this->validateCreateRequest($request);
$administrator = $this->administratorRepository->findOneByLoginCredentials(
$request->get('login_name'),
$request->get('password')
);
if ($administrator === null) {
throw new UnauthorizedHttpException('', 'Not authorized', null, 1500567098);
}
$token = $this->createAndPersistToken($administrator);
return View::create()->setStatusCode(Response::HTTP_CREATED)->setData($token);
}
/**
* Deletes a session.
*
* This action may only be called for sessions that are owned by the authenticated administrator.
*
* @param Request $request
* @param AdministratorToken $token
*
* @return View
*
* @throws AccessDeniedHttpException
*/
public function deleteAction(Request $request, AdministratorToken $token): View
{
$administrator = $this->requireAuthentication($request);
if ($token->getAdministrator() !== $administrator) {
throw new AccessDeniedHttpException('You do not have access to this session.', null, 1519831644);
}
$this->tokenRepository->remove($token);
return View::create();
}
/**
* Validates the request. If is it not valid, throws an exception.
*
* @param Request $request
*
* @return void
*
* @throws BadRequestHttpException
*/
private function validateCreateRequest(Request $request)
{
if ($request->getContent() === '') {
throw new BadRequestHttpException('Empty JSON data', null, 1500559729);
}
if (empty($request->get('login_name')) || empty($request->get('password'))) {
throw new BadRequestHttpException('Incomplete credentials', null, 1500562647);
}
}
/**
* @param Administrator $administrator
*
* @return AdministratorToken
*/
private function createAndPersistToken(Administrator $administrator): AdministratorToken
{
$token = new AdministratorToken();
$token->setAdministrator($administrator);
$token->generateExpiry();
$token->generateKey();
$this->tokenRepository->save($token);
return $token;
}
}