Improved AuthenticationMiddleware API tests

This commit is contained in:
Alejandro Celaya 2019-11-26 21:29:25 +01:00
parent 13e795d25d
commit 509c9fe2e8
10 changed files with 57 additions and 33 deletions

View file

@ -36,10 +36,7 @@ class RequestToHttpAuthPlugin implements RequestToHttpAuthPluginInterface
public function fromRequest(ServerRequestInterface $request): Plugin\AuthenticationPluginInterface public function fromRequest(ServerRequestInterface $request): Plugin\AuthenticationPluginInterface
{ {
if (! $this->hasAnySupportedHeader($request)) { if (! $this->hasAnySupportedHeader($request)) {
throw NoAuthenticationException::fromExpectedTypes([ throw NoAuthenticationException::fromExpectedTypes(self::SUPPORTED_AUTH_HEADERS);
Plugin\ApiKeyHeaderPlugin::HEADER_NAME,
Plugin\AuthorizationHeaderPlugin::HEADER_NAME,
]);
} }
return $this->authPluginManager->get($this->getFirstAvailableHeader($request)); return $this->authPluginManager->get($this->getFirstAvailableHeader($request));

View file

@ -21,12 +21,6 @@ class CreateShortUrlContentNegotiationMiddleware implements MiddlewareInterface
private const PLAIN_TEXT = 'text'; private const PLAIN_TEXT = 'text';
private const JSON = 'json'; private const JSON = 'json';
/**
* Process an incoming server request and return a response, optionally delegating
* response creation to a handler.
* @throws \RuntimeException
* @throws \InvalidArgumentException
*/
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
{ {
$response = $handler->handle($request); $response = $handler->handle($request);

View file

@ -6,7 +6,6 @@ namespace ShlinkioApiTest\Shlink\Rest\Action;
use Cake\Chronos\Chronos; use Cake\Chronos\Chronos;
use GuzzleHttp\RequestOptions; use GuzzleHttp\RequestOptions;
use Shlinkio\Shlink\Rest\Util\RestUtils;
use Shlinkio\Shlink\TestUtils\ApiTest\ApiTestCase; use Shlinkio\Shlink\TestUtils\ApiTest\ApiTestCase;
use function Functional\map; use function Functional\map;
@ -44,7 +43,7 @@ class CreateShortUrlActionTest extends ApiTestCase
[$statusCode, $payload] = $this->createShortUrl(['customSlug' => $slug, 'domain' => $domain]); [$statusCode, $payload] = $this->createShortUrl(['customSlug' => $slug, 'domain' => $domain]);
$this->assertEquals(self::STATUS_BAD_REQUEST, $statusCode); $this->assertEquals(self::STATUS_BAD_REQUEST, $statusCode);
$this->assertEquals(RestUtils::INVALID_SLUG_ERROR, $payload['error']); $this->assertEquals('INVALID_SLUG', $payload['error']);
} }
/** @test */ /** @test */

View file

@ -4,7 +4,6 @@ declare(strict_types=1);
namespace ShlinkioApiTest\Shlink\Rest\Action; namespace ShlinkioApiTest\Shlink\Rest\Action;
use Shlinkio\Shlink\Rest\Util\RestUtils;
use Shlinkio\Shlink\TestUtils\ApiTest\ApiTestCase; use Shlinkio\Shlink\TestUtils\ApiTest\ApiTestCase;
class DeleteShortUrlActionTest extends ApiTestCase class DeleteShortUrlActionTest extends ApiTestCase
@ -16,7 +15,7 @@ class DeleteShortUrlActionTest extends ApiTestCase
['error' => $error] = $this->getJsonResponsePayload($resp); ['error' => $error] = $this->getJsonResponsePayload($resp);
$this->assertEquals(self::STATUS_NOT_FOUND, $resp->getStatusCode()); $this->assertEquals(self::STATUS_NOT_FOUND, $resp->getStatusCode());
$this->assertEquals(RestUtils::INVALID_SHORTCODE_ERROR, $error); $this->assertEquals('INVALID_SHORTCODE', $error);
} }
/** @test */ /** @test */
@ -31,6 +30,6 @@ class DeleteShortUrlActionTest extends ApiTestCase
['error' => $error] = $this->getJsonResponsePayload($resp); ['error' => $error] = $this->getJsonResponsePayload($resp);
$this->assertEquals(self::STATUS_UNPROCESSABLE_ENTITY, $resp->getStatusCode()); $this->assertEquals(self::STATUS_UNPROCESSABLE_ENTITY, $resp->getStatusCode());
$this->assertEquals(RestUtils::INVALID_SHORTCODE_DELETION_ERROR, $error); $this->assertEquals('INVALID_SHORTCODE_DELETION', $error);
} }
} }

View file

@ -5,7 +5,6 @@ declare(strict_types=1);
namespace ShlinkioApiTest\Shlink\Rest\Action; namespace ShlinkioApiTest\Shlink\Rest\Action;
use GuzzleHttp\RequestOptions; use GuzzleHttp\RequestOptions;
use Shlinkio\Shlink\Rest\Util\RestUtils;
use Shlinkio\Shlink\TestUtils\ApiTest\ApiTestCase; use Shlinkio\Shlink\TestUtils\ApiTest\ApiTestCase;
class EditShortUrlActionTagsTest extends ApiTestCase class EditShortUrlActionTagsTest extends ApiTestCase
@ -17,7 +16,7 @@ class EditShortUrlActionTagsTest extends ApiTestCase
['error' => $error] = $this->getJsonResponsePayload($resp); ['error' => $error] = $this->getJsonResponsePayload($resp);
$this->assertEquals(self::STATUS_BAD_REQUEST, $resp->getStatusCode()); $this->assertEquals(self::STATUS_BAD_REQUEST, $resp->getStatusCode());
$this->assertEquals(RestUtils::INVALID_ARGUMENT_ERROR, $error); $this->assertEquals('INVALID_ARGUMENT', $error);
} }
/** @test */ /** @test */
@ -29,6 +28,6 @@ class EditShortUrlActionTagsTest extends ApiTestCase
['error' => $error] = $this->getJsonResponsePayload($resp); ['error' => $error] = $this->getJsonResponsePayload($resp);
$this->assertEquals(self::STATUS_NOT_FOUND, $resp->getStatusCode()); $this->assertEquals(self::STATUS_NOT_FOUND, $resp->getStatusCode());
$this->assertEquals(RestUtils::INVALID_SHORTCODE_ERROR, $error); $this->assertEquals('INVALID_SHORTCODE', $error);
} }
} }

View file

@ -5,7 +5,6 @@ declare(strict_types=1);
namespace ShlinkioApiTest\Shlink\Rest\Action; namespace ShlinkioApiTest\Shlink\Rest\Action;
use GuzzleHttp\RequestOptions; use GuzzleHttp\RequestOptions;
use Shlinkio\Shlink\Rest\Util\RestUtils;
use Shlinkio\Shlink\TestUtils\ApiTest\ApiTestCase; use Shlinkio\Shlink\TestUtils\ApiTest\ApiTestCase;
class EditShortUrlActionTest extends ApiTestCase class EditShortUrlActionTest extends ApiTestCase
@ -17,7 +16,7 @@ class EditShortUrlActionTest extends ApiTestCase
['error' => $error] = $this->getJsonResponsePayload($resp); ['error' => $error] = $this->getJsonResponsePayload($resp);
$this->assertEquals(self::STATUS_NOT_FOUND, $resp->getStatusCode()); $this->assertEquals(self::STATUS_NOT_FOUND, $resp->getStatusCode());
$this->assertEquals(RestUtils::INVALID_SHORTCODE_ERROR, $error); $this->assertEquals('INVALID_SHORTCODE', $error);
} }
/** @test */ /** @test */
@ -29,6 +28,6 @@ class EditShortUrlActionTest extends ApiTestCase
['error' => $error] = $this->getJsonResponsePayload($resp); ['error' => $error] = $this->getJsonResponsePayload($resp);
$this->assertEquals(self::STATUS_BAD_REQUEST, $resp->getStatusCode()); $this->assertEquals(self::STATUS_BAD_REQUEST, $resp->getStatusCode());
$this->assertEquals(RestUtils::INVALID_ARGUMENT_ERROR, $error); $this->assertEquals('INVALID_ARGUMENT', $error);
} }
} }

View file

@ -4,7 +4,6 @@ declare(strict_types=1);
namespace ShlinkioApiTest\Shlink\Rest\Action; namespace ShlinkioApiTest\Shlink\Rest\Action;
use Shlinkio\Shlink\Rest\Util\RestUtils;
use Shlinkio\Shlink\TestUtils\ApiTest\ApiTestCase; use Shlinkio\Shlink\TestUtils\ApiTest\ApiTestCase;
class GetVisitsActionTest extends ApiTestCase class GetVisitsActionTest extends ApiTestCase
@ -16,6 +15,6 @@ class GetVisitsActionTest extends ApiTestCase
['error' => $error] = $this->getJsonResponsePayload($resp); ['error' => $error] = $this->getJsonResponsePayload($resp);
$this->assertEquals(self::STATUS_NOT_FOUND, $resp->getStatusCode()); $this->assertEquals(self::STATUS_NOT_FOUND, $resp->getStatusCode());
$this->assertEquals(RestUtils::INVALID_SHORTCODE_ERROR, $error); $this->assertEquals('INVALID_SHORTCODE', $error);
} }
} }

View file

@ -4,7 +4,6 @@ declare(strict_types=1);
namespace ShlinkioApiTest\Shlink\Rest\Action; namespace ShlinkioApiTest\Shlink\Rest\Action;
use Shlinkio\Shlink\Rest\Util\RestUtils;
use Shlinkio\Shlink\TestUtils\ApiTest\ApiTestCase; use Shlinkio\Shlink\TestUtils\ApiTest\ApiTestCase;
class ResolveShortUrlActionTest extends ApiTestCase class ResolveShortUrlActionTest extends ApiTestCase
@ -16,6 +15,6 @@ class ResolveShortUrlActionTest extends ApiTestCase
['error' => $error] = $this->getJsonResponsePayload($resp); ['error' => $error] = $this->getJsonResponsePayload($resp);
$this->assertEquals(self::STATUS_NOT_FOUND, $resp->getStatusCode()); $this->assertEquals(self::STATUS_NOT_FOUND, $resp->getStatusCode());
$this->assertEquals(RestUtils::INVALID_SHORTCODE_ERROR, $error); $this->assertEquals('INVALID_SHORTCODE', $error);
} }
} }

View file

@ -5,7 +5,6 @@ declare(strict_types=1);
namespace ShlinkioApiTest\Shlink\Rest\Action; namespace ShlinkioApiTest\Shlink\Rest\Action;
use GuzzleHttp\RequestOptions; use GuzzleHttp\RequestOptions;
use Shlinkio\Shlink\Rest\Util\RestUtils;
use Shlinkio\Shlink\TestUtils\ApiTest\ApiTestCase; use Shlinkio\Shlink\TestUtils\ApiTest\ApiTestCase;
class UpdateTagActionTest extends ApiTestCase class UpdateTagActionTest extends ApiTestCase
@ -20,7 +19,7 @@ class UpdateTagActionTest extends ApiTestCase
['error' => $error] = $this->getJsonResponsePayload($resp); ['error' => $error] = $this->getJsonResponsePayload($resp);
$this->assertEquals(self::STATUS_BAD_REQUEST, $resp->getStatusCode()); $this->assertEquals(self::STATUS_BAD_REQUEST, $resp->getStatusCode());
$this->assertEquals(RestUtils::INVALID_ARGUMENT_ERROR, $error); $this->assertEquals('INVALID_ARGUMENT', $error);
} }
public function provideInvalidBody(): iterable public function provideInvalidBody(): iterable
@ -40,6 +39,6 @@ class UpdateTagActionTest extends ApiTestCase
['error' => $error] = $this->getJsonResponsePayload($resp); ['error' => $error] = $this->getJsonResponsePayload($resp);
$this->assertEquals(self::STATUS_NOT_FOUND, $resp->getStatusCode()); $this->assertEquals(self::STATUS_NOT_FOUND, $resp->getStatusCode());
$this->assertEquals(RestUtils::NOT_FOUND_ERROR, $error); $this->assertEquals('TAG_NOT_FOUND', $error);
} }
} }

View file

@ -4,9 +4,8 @@ declare(strict_types=1);
namespace ShlinkioApiTest\Shlink\Rest\Middleware; namespace ShlinkioApiTest\Shlink\Rest\Middleware;
use Shlinkio\Shlink\Rest\Authentication\Plugin\ApiKeyHeaderPlugin; use Shlinkio\Shlink\Rest\Authentication\Plugin;
use Shlinkio\Shlink\Rest\Authentication\RequestToHttpAuthPlugin; use Shlinkio\Shlink\Rest\Authentication\RequestToHttpAuthPlugin;
use Shlinkio\Shlink\Rest\Util\RestUtils;
use Shlinkio\Shlink\TestUtils\ApiTest\ApiTestCase; use Shlinkio\Shlink\TestUtils\ApiTest\ApiTestCase;
use function implode; use function implode;
@ -21,7 +20,7 @@ class AuthenticationTest extends ApiTestCase
['error' => $error, 'message' => $message] = $this->getJsonResponsePayload($resp); ['error' => $error, 'message' => $message] = $this->getJsonResponsePayload($resp);
$this->assertEquals(self::STATUS_UNAUTHORIZED, $resp->getStatusCode()); $this->assertEquals(self::STATUS_UNAUTHORIZED, $resp->getStatusCode());
$this->assertEquals(RestUtils::INVALID_AUTHORIZATION_ERROR, $error); $this->assertEquals('INVALID_AUTHORIZATION', $error);
$this->assertEquals( $this->assertEquals(
sprintf( sprintf(
'Expected one of the following authentication headers, but none were provided, ["%s"]', 'Expected one of the following authentication headers, but none were provided, ["%s"]',
@ -39,13 +38,13 @@ class AuthenticationTest extends ApiTestCase
{ {
$resp = $this->callApi(self::METHOD_GET, '/short-codes', [ $resp = $this->callApi(self::METHOD_GET, '/short-codes', [
'headers' => [ 'headers' => [
ApiKeyHeaderPlugin::HEADER_NAME => $apiKey, Plugin\ApiKeyHeaderPlugin::HEADER_NAME => $apiKey,
], ],
]); ]);
['error' => $error, 'message' => $message] = $this->getJsonResponsePayload($resp); ['error' => $error, 'message' => $message] = $this->getJsonResponsePayload($resp);
$this->assertEquals(self::STATUS_UNAUTHORIZED, $resp->getStatusCode()); $this->assertEquals(self::STATUS_UNAUTHORIZED, $resp->getStatusCode());
$this->assertEquals(RestUtils::INVALID_API_KEY_ERROR, $error); $this->assertEquals('INVALID_API_KEY', $error);
$this->assertEquals('Provided API key does not exist or is invalid.', $message); $this->assertEquals('Provided API key does not exist or is invalid.', $message);
} }
@ -55,4 +54,45 @@ class AuthenticationTest extends ApiTestCase
yield 'key which is expired' => ['expired_api_key']; yield 'key which is expired' => ['expired_api_key'];
yield 'key which is disabled' => ['disabled_api_key']; yield 'key which is disabled' => ['disabled_api_key'];
} }
/**
* @test
* @dataProvider provideInvalidAuthorizations
*/
public function authorizationErrorIsReturnedIfInvalidDataIsProvided(
string $authValue,
string $expectedMessage,
string $expectedError
): void {
$resp = $this->callApi(self::METHOD_GET, '/short-codes', [
'headers' => [
Plugin\AuthorizationHeaderPlugin::HEADER_NAME => $authValue,
],
]);
['error' => $error, 'message' => $message] = $this->getJsonResponsePayload($resp);
$this->assertEquals(self::STATUS_UNAUTHORIZED, $resp->getStatusCode());
$this->assertEquals($expectedError, $error);
$this->assertEquals($expectedMessage, $message);
}
public function provideInvalidAuthorizations(): iterable
{
yield 'no type' => [
'invalid',
'You need to provide the Bearer type in the Authorization header.',
'INVALID_AUTHORIZATION',
];
yield 'invalid type' => [
'Basic invalid',
'Provided authorization type Basic is not supported. Use Bearer instead.',
'INVALID_AUTHORIZATION',
];
yield 'invalid JWT' => [
'Bearer invalid',
'Missing or invalid auth token provided. Perform a new authentication request and send provided '
. 'token on every new request on the Authorization header',
'INVALID_AUTH_TOKEN',
];
}
} }