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 Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use Shlinkio\Shlink\Rest\Exception\AuthenticationException;
use Shlinkio\Shlink\Rest\Service\RestTokenService;
use Shlinkio\Shlink\Rest\Service\RestTokenServiceInterface;
use Shlinkio\Shlink\Rest\Service\ApiKeyService;
use Shlinkio\Shlink\Rest\Service\ApiKeyServiceInterface;
use Shlinkio\Shlink\Rest\Util\RestUtils;
use Zend\Diactoros\Response\JsonResponse;
use Zend\I18n\Translator\TranslatorInterface;
class AuthenticateAction extends AbstractRestAction
{
/**
* @var RestTokenServiceInterface
*/
private $restTokenService;
/**
* @var TranslatorInterface
*/
private $translator;
/**
* @var ApiKeyService|ApiKeyServiceInterface
*/
private $apiKeyService;
/**
* AuthenticateAction constructor.
* @param RestTokenServiceInterface|RestTokenService $restTokenService
* @param ApiKeyServiceInterface|ApiKeyService $apiKeyService
* @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->apiKeyService = $apiKeyService;
}
/**
@ -44,7 +43,7 @@ class AuthenticateAction extends AbstractRestAction
public function dispatch(Request $request, Response $response, callable $out = null)
{
$authData = $request->getParsedBody();
if (! isset($authData['apiKey']) && ! isset($authData['username'], $authData['password'])) {
if (! isset($authData['apiKey'])) {
return new JsonResponse([
'error' => RestUtils::INVALID_ARGUMENT_ERROR,
'message' => $this->translator->translate(
@ -53,14 +52,16 @@ class AuthenticateAction extends AbstractRestAction
], 400);
}
try {
$token = $this->restTokenService->createToken($authData['username'], $authData['password']);
return new JsonResponse(['token' => $token->getToken()]);
} catch (AuthenticationException $e) {
// Authenticate using provided API key
if (! $this->apiKeyService->check($authData['apiKey'])) {
return new JsonResponse([
'error' => RestUtils::getRestErrorCodeFromException($e),
'message' => $this->translator->translate('Invalid username and/or password'),
'error' => RestUtils::INVALID_API_KEY_ERROR,
'message' => $this->translator->translate('Provided API key does not exist or is invalid.'),
], 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_CREDENTIALS_ERROR = 'INVALID_CREDENTIALS';
const INVALID_AUTH_TOKEN_ERROR = 'INVALID_AUTH_TOKEN';
const INVALID_API_KEY_ERROR = 'INVALID_API_KEY';
const NOT_FOUND_ERROR = 'NOT_FOUND';
const UNKNOWN_ERROR = 'UNKNOWN_ERROR';

View File

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