diff --git a/module/Rest/config/auth.config.php b/module/Rest/config/auth.config.php index 94e853be..8786e202 100644 --- a/module/Rest/config/auth.config.php +++ b/module/Rest/config/auth.config.php @@ -39,6 +39,7 @@ return [ ConfigAbstractFactory::class => [ Authentication\Plugin\AuthorizationHeaderPlugin::class => [Authentication\JWTService::class, 'translator'], + Authentication\Plugin\ApiKeyHeaderPlugin::class => [Service\ApiKeyService::class, 'translator'], Authentication\RequestToHttpAuthPlugin::class => [Authentication\AuthenticationPluginManager::class], diff --git a/module/Rest/src/Authentication/Plugin/ApiKeyHeaderPlugin.php b/module/Rest/src/Authentication/Plugin/ApiKeyHeaderPlugin.php index ccfa7eee..fcf41b96 100644 --- a/module/Rest/src/Authentication/Plugin/ApiKeyHeaderPlugin.php +++ b/module/Rest/src/Authentication/Plugin/ApiKeyHeaderPlugin.php @@ -6,17 +6,43 @@ namespace Shlinkio\Shlink\Rest\Authentication\Plugin; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; use Shlinkio\Shlink\Rest\Exception\VerifyAuthenticationException; +use Shlinkio\Shlink\Rest\Service\ApiKeyServiceInterface; +use Shlinkio\Shlink\Rest\Util\RestUtils; +use Zend\I18n\Translator\TranslatorInterface; class ApiKeyHeaderPlugin implements AuthenticationPluginInterface { public const HEADER_NAME = 'X-Api-Key'; + /** + * @var ApiKeyServiceInterface + */ + private $apiKeyService; + /** + * @var TranslatorInterface + */ + private $translator; + + public function __construct(ApiKeyServiceInterface $apiKeyService, TranslatorInterface $translator) + { + $this->apiKeyService = $apiKeyService; + $this->translator = $translator; + } + /** * @throws VerifyAuthenticationException */ public function verify(ServerRequestInterface $request): void { - // TODO: Implement check() method. + $apiKey = $request->getHeaderLine(self::HEADER_NAME); + if ($this->apiKeyService->check($apiKey)) { + return; + } + + throw VerifyAuthenticationException::withError( + RestUtils::INVALID_API_KEY_ERROR, + $this->translator->translate('Provided API key does not exist or is invalid.') + ); } public function update(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface diff --git a/module/Rest/test/Authentication/Plugin/ApiKeyHeaderPluginTest.php b/module/Rest/test/Authentication/Plugin/ApiKeyHeaderPluginTest.php new file mode 100644 index 00000000..fef86e71 --- /dev/null +++ b/module/Rest/test/Authentication/Plugin/ApiKeyHeaderPluginTest.php @@ -0,0 +1,78 @@ +apiKeyService = $this->prophesize(ApiKeyServiceInterface::class); + $this->plugin = new ApiKeyHeaderPlugin($this->apiKeyService->reveal(), Translator::factory([])); + } + + /** + * @test + */ + public function verifyThrowsExceptionWhenApiKeyIsNotValid() + { + $apiKey = 'abc-ABC'; + $check = $this->apiKeyService->check($apiKey)->willReturn(false); + $check->shouldBeCalledTimes(1); + + $this->expectException(VerifyAuthenticationException::class); + $this->expectExceptionMessage('Provided API key does not exist or is invalid'); + + $this->plugin->verify($this->createRequest($apiKey)); + } + + /** + * @test + */ + public function verifyDoesNotThrowExceptionWhenApiKeyIsValid() + { + $apiKey = 'abc-ABC'; + $check = $this->apiKeyService->check($apiKey)->willReturn(true); + + $this->plugin->verify($this->createRequest($apiKey)); + + $check->shouldHaveBeenCalledTimes(1); + } + + /** + * @test + */ + public function updateReturnsResponseAsIs() + { + $apiKey = 'abc-ABC'; + $response = new Response(); + + $returnedResponse = $this->plugin->update($this->createRequest($apiKey), $response); + + $this->assertSame($response, $returnedResponse); + } + + private function createRequest(string $apiKey): ServerRequestInterface + { + return ServerRequestFactory::fromGlobals()->withHeader(ApiKeyHeaderPlugin::HEADER_NAME, $apiKey); + } +}