Updated AuthenticateAction to use the APiKeyService instead of the RestTokenService

This commit is contained in:
Alejandro Celaya 2016-08-07 10:26:34 +02:00
parent 289db45f27
commit 1d92e87d50
3 changed files with 33 additions and 36 deletions

View File

@ -4,35 +4,34 @@ namespace Shlinkio\Shlink\Rest\Action;
use Acelaya\ZsmAnnotatedServices\Annotation\Inject; use Acelaya\ZsmAnnotatedServices\Annotation\Inject;
use Psr\Http\Message\ResponseInterface as Response; use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request; use Psr\Http\Message\ServerRequestInterface as Request;
use Shlinkio\Shlink\Rest\Exception\AuthenticationException; use Shlinkio\Shlink\Rest\Service\ApiKeyService;
use Shlinkio\Shlink\Rest\Service\RestTokenService; use Shlinkio\Shlink\Rest\Service\ApiKeyServiceInterface;
use Shlinkio\Shlink\Rest\Service\RestTokenServiceInterface;
use Shlinkio\Shlink\Rest\Util\RestUtils; use Shlinkio\Shlink\Rest\Util\RestUtils;
use Zend\Diactoros\Response\JsonResponse; use Zend\Diactoros\Response\JsonResponse;
use Zend\I18n\Translator\TranslatorInterface; use Zend\I18n\Translator\TranslatorInterface;
class AuthenticateAction extends AbstractRestAction class AuthenticateAction extends AbstractRestAction
{ {
/**
* @var RestTokenServiceInterface
*/
private $restTokenService;
/** /**
* @var TranslatorInterface * @var TranslatorInterface
*/ */
private $translator; private $translator;
/**
* @var ApiKeyService|ApiKeyServiceInterface
*/
private $apiKeyService;
/** /**
* AuthenticateAction constructor. * AuthenticateAction constructor.
* @param RestTokenServiceInterface|RestTokenService $restTokenService * @param ApiKeyServiceInterface|ApiKeyService $apiKeyService
* @param TranslatorInterface $translator * @param TranslatorInterface $translator
* *
* @Inject({RestTokenService::class, "translator"}) * @Inject({ApiKeyService::class, "translator"})
*/ */
public function __construct(RestTokenServiceInterface $restTokenService, TranslatorInterface $translator) public function __construct(ApiKeyServiceInterface $apiKeyService, TranslatorInterface $translator)
{ {
$this->restTokenService = $restTokenService;
$this->translator = $translator; $this->translator = $translator;
$this->apiKeyService = $apiKeyService;
} }
/** /**
@ -44,7 +43,7 @@ class AuthenticateAction extends AbstractRestAction
public function dispatch(Request $request, Response $response, callable $out = null) public function dispatch(Request $request, Response $response, callable $out = null)
{ {
$authData = $request->getParsedBody(); $authData = $request->getParsedBody();
if (! isset($authData['apiKey']) && ! isset($authData['username'], $authData['password'])) { if (! isset($authData['apiKey'])) {
return new JsonResponse([ return new JsonResponse([
'error' => RestUtils::INVALID_ARGUMENT_ERROR, 'error' => RestUtils::INVALID_ARGUMENT_ERROR,
'message' => $this->translator->translate( 'message' => $this->translator->translate(
@ -53,14 +52,16 @@ class AuthenticateAction extends AbstractRestAction
], 400); ], 400);
} }
try { // Authenticate using provided API key
$token = $this->restTokenService->createToken($authData['username'], $authData['password']); if (! $this->apiKeyService->check($authData['apiKey'])) {
return new JsonResponse(['token' => $token->getToken()]);
} catch (AuthenticationException $e) {
return new JsonResponse([ return new JsonResponse([
'error' => RestUtils::getRestErrorCodeFromException($e), 'error' => RestUtils::INVALID_API_KEY_ERROR,
'message' => $this->translator->translate('Invalid username and/or password'), 'message' => $this->translator->translate('Provided API key does not exist or is invalid.'),
], 401); ], 401);
} }
// TODO Generate a JSON Web Token that will be used for authorization in next requests
return new JsonResponse(['token' => '']);
} }
} }

View File

@ -12,6 +12,7 @@ class RestUtils
const INVALID_ARGUMENT_ERROR = 'INVALID_ARGUMENT'; const INVALID_ARGUMENT_ERROR = 'INVALID_ARGUMENT';
const INVALID_CREDENTIALS_ERROR = 'INVALID_CREDENTIALS'; const INVALID_CREDENTIALS_ERROR = 'INVALID_CREDENTIALS';
const INVALID_AUTH_TOKEN_ERROR = 'INVALID_AUTH_TOKEN'; const INVALID_AUTH_TOKEN_ERROR = 'INVALID_AUTH_TOKEN';
const INVALID_API_KEY_ERROR = 'INVALID_API_KEY';
const NOT_FOUND_ERROR = 'NOT_FOUND'; const NOT_FOUND_ERROR = 'NOT_FOUND';
const UNKNOWN_ERROR = 'UNKNOWN_ERROR'; const UNKNOWN_ERROR = 'UNKNOWN_ERROR';

View File

@ -3,10 +3,8 @@ namespace ShlinkioTest\Shlink\Rest\Action;
use PHPUnit_Framework_TestCase as TestCase; use PHPUnit_Framework_TestCase as TestCase;
use Prophecy\Prophecy\ObjectProphecy; use Prophecy\Prophecy\ObjectProphecy;
use Shlinkio\Shlink\Core\Entity\RestToken;
use Shlinkio\Shlink\Rest\Action\AuthenticateAction; use Shlinkio\Shlink\Rest\Action\AuthenticateAction;
use Shlinkio\Shlink\Rest\Exception\AuthenticationException; use Shlinkio\Shlink\Rest\Service\ApiKeyService;
use Shlinkio\Shlink\Rest\Service\RestTokenService;
use Zend\Diactoros\Response; use Zend\Diactoros\Response;
use Zend\Diactoros\ServerRequestFactory; use Zend\Diactoros\ServerRequestFactory;
use Zend\I18n\Translator\Translator; use Zend\I18n\Translator\Translator;
@ -20,12 +18,12 @@ class AuthenticateActionTest extends TestCase
/** /**
* @var ObjectProphecy * @var ObjectProphecy
*/ */
protected $tokenService; protected $apiKeyService;
public function setUp() public function setUp()
{ {
$this->tokenService = $this->prophesize(RestTokenService::class); $this->apiKeyService = $this->prophesize(ApiKeyService::class);
$this->action = new AuthenticateAction($this->tokenService->reveal(), Translator::factory([])); $this->action = new AuthenticateAction($this->apiKeyService->reveal(), Translator::factory([]));
} }
/** /**
@ -40,34 +38,31 @@ class AuthenticateActionTest extends TestCase
/** /**
* @test * @test
*/ */
public function properCredentialsReturnTokenInResponse() public function properApiKeyReturnsTokenInResponse()
{ {
$this->tokenService->createToken('foo', 'bar')->willReturn( $this->apiKeyService->check('foo')->willReturn(true)
(new RestToken())->setToken('abc-ABC') ->shouldBeCalledTimes(1);
)->shouldBeCalledTimes(1);
$request = ServerRequestFactory::fromGlobals()->withParsedBody([ $request = ServerRequestFactory::fromGlobals()->withParsedBody([
'username' => 'foo', 'apiKey' => 'foo',
'password' => 'bar',
]); ]);
$response = $this->action->__invoke($request, new Response()); $response = $this->action->__invoke($request, new Response());
$this->assertEquals(200, $response->getStatusCode()); $this->assertEquals(200, $response->getStatusCode());
$response->getBody()->rewind(); $response->getBody()->rewind();
$this->assertEquals(['token' => 'abc-ABC'], json_decode($response->getBody()->getContents(), true)); $this->assertTrue(strpos($response->getBody()->getContents(), '"token"') > 0);
} }
/** /**
* @test * @test
*/ */
public function authenticationExceptionsReturnErrorResponse() public function invalidApiKeyReturnsErrorResponse()
{ {
$this->tokenService->createToken('foo', 'bar')->willThrow(new AuthenticationException()) $this->apiKeyService->check('foo')->willReturn(false)
->shouldBeCalledTimes(1); ->shouldBeCalledTimes(1);
$request = ServerRequestFactory::fromGlobals()->withParsedBody([ $request = ServerRequestFactory::fromGlobals()->withParsedBody([
'username' => 'foo', 'apiKey' => 'foo',
'password' => 'bar',
]); ]);
$response = $this->action->__invoke($request, new Response()); $response = $this->action->__invoke($request, new Response());
$this->assertEquals(401, $response->getStatusCode()); $this->assertEquals(401, $response->getStatusCode());