feat: require the CMS API key on /api/hotel and /api/product
This commit is contained in:
1 parent
7839b97e63
commit
32b70f9b70
3 files changed
+51
-21
No files matched your search
@@ -1,12 +1,42 @@
|
|||||||
|
# Backchannel endpoints MyE&P reads hotel and product data from. Same environment files and key
|
||||||
|
# as content-feed.http: pick "local" and put cmsApiKey in http-client.private.env.json.
|
||||||
|
|
||||||
### GET product data for myep
|
### GET product data for myep
|
||||||
GET https://ep-reisen.ddev.site/api/product
|
GET {{host}}/api/product?product=3VIIN&hotel=VLTS
|
||||||
?product=SSTMR
|
X-Api-Key: {{cmsApiKey}}
|
||||||
&hotel=SSTGR
|
|
||||||
&key=abcabc123
|
> {%
|
||||||
|
client.test("200 with key", function () {
|
||||||
|
client.assert(response.status === 200, "expected 200, got " + response.status);
|
||||||
|
});
|
||||||
|
%}
|
||||||
|
|
||||||
### GET hotel data for myep
|
### GET hotel data for myep
|
||||||
GET https://ep-reisen.ddev.site/api/hotel
|
GET {{host}}/api/hotel?hotel=DPWGRP
|
||||||
?hotel=DPWGRP
|
X-Api-Key: {{cmsApiKey}}
|
||||||
&key=abcabc123
|
|
||||||
|
> {%
|
||||||
|
client.test("200 with key", function () {
|
||||||
|
client.assert(response.status === 200, "expected 200, got " + response.status);
|
||||||
|
});
|
||||||
|
%}
|
||||||
|
|
||||||
|
### Transition form: key as query parameter, as MyE&P sends it today (still accepted)
|
||||||
|
GET {{host}}/api/hotel?hotel=DPWGRP&key={{cmsApiKey}}
|
||||||
|
|
||||||
|
> {%
|
||||||
|
client.test("200 with query key", function () {
|
||||||
|
client.assert(response.status === 200, "expected 200, got " + response.status);
|
||||||
|
});
|
||||||
|
%}
|
||||||
|
|
||||||
|
### Any other value is refused now - this used to pass
|
||||||
|
GET {{host}}/api/hotel?hotel=DPWGRP&key=AbcAbc123
|
||||||
|
|
||||||
|
> {%
|
||||||
|
client.test("403 with the old dummy key", function () {
|
||||||
|
client.assert(response.status === 403, "expected 403, got " + response.status);
|
||||||
|
});
|
||||||
|
%}
|
||||||
|
|
||||||
###
|
###
|
||||||
@@ -3,6 +3,7 @@
|
|||||||
namespace EP\EpProducts\Middleware;
|
namespace EP\EpProducts\Middleware;
|
||||||
|
|
||||||
use EP\EpProducts\ContentFeed\ContentFeedApi;
|
use EP\EpProducts\ContentFeed\ContentFeedApi;
|
||||||
|
use EP\EpProducts\Http\ApiKeyAuthenticator;
|
||||||
use EP\EpProducts\Service\MyEpImageService;
|
use EP\EpProducts\Service\MyEpImageService;
|
||||||
use EP\EpProducts\Utility\HotelIconUtility;
|
use EP\EpProducts\Utility\HotelIconUtility;
|
||||||
use Psr\Http\Message\ResponseInterface;
|
use Psr\Http\Message\ResponseInterface;
|
||||||
@@ -47,13 +48,19 @@ class ApiMiddleware implements MiddlewareInterface
|
|||||||
*/
|
*/
|
||||||
private $contentFeedApi;
|
private $contentFeedApi;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var ApiKeyAuthenticator
|
||||||
|
*/
|
||||||
|
private $authenticator;
|
||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
MyEpImageService $hotelImageService,
|
MyEpImageService $hotelImageService,
|
||||||
MyEpImageService $productImageService,
|
MyEpImageService $productImageService,
|
||||||
MyEpImageService $regionImageService,
|
MyEpImageService $regionImageService,
|
||||||
FileRepository $fileRepository,
|
FileRepository $fileRepository,
|
||||||
ImageService $imageService,
|
ImageService $imageService,
|
||||||
ContentFeedApi $contentFeedApi
|
ContentFeedApi $contentFeedApi,
|
||||||
|
ApiKeyAuthenticator $authenticator
|
||||||
) {
|
) {
|
||||||
$this->hotelImageService = $hotelImageService;
|
$this->hotelImageService = $hotelImageService;
|
||||||
$this->productImageService = $productImageService;
|
$this->productImageService = $productImageService;
|
||||||
@@ -61,6 +68,7 @@ class ApiMiddleware implements MiddlewareInterface
|
|||||||
$this->fileRepository = $fileRepository;
|
$this->fileRepository = $fileRepository;
|
||||||
$this->imageService = $imageService;
|
$this->imageService = $imageService;
|
||||||
$this->contentFeedApi = $contentFeedApi;
|
$this->contentFeedApi = $contentFeedApi;
|
||||||
|
$this->authenticator = $authenticator;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
|
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
|
||||||
@@ -84,12 +92,8 @@ class ApiMiddleware implements MiddlewareInterface
|
|||||||
|
|
||||||
private function handleHotelRequest(ServerRequestInterface $request): ResponseInterface
|
private function handleHotelRequest(ServerRequestInterface $request): ResponseInterface
|
||||||
{
|
{
|
||||||
// This is currently fake, we only check for existence. Since we are communicating
|
if (!$this->authenticator->isAuthorized($request)) {
|
||||||
// on the backchannel only it's not much of a problem.
|
return new JsonResponse(['message' => 'Invalid or missing api key'], 403);
|
||||||
$apiKey = $request->getQueryParams()['key'] ?? null;
|
|
||||||
|
|
||||||
if (null === $apiKey) {
|
|
||||||
return new JsonResponse(['message' => 'No api key provided'], 403);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$hotelCode = $request->getQueryParams()['hotel'] ?? null;
|
$hotelCode = $request->getQueryParams()['hotel'] ?? null;
|
||||||
@@ -109,12 +113,8 @@ class ApiMiddleware implements MiddlewareInterface
|
|||||||
|
|
||||||
private function handleProductRequest(ServerRequestInterface $request): ResponseInterface
|
private function handleProductRequest(ServerRequestInterface $request): ResponseInterface
|
||||||
{
|
{
|
||||||
// This is currently fake, we only check for existence. Since we are communicating
|
if (!$this->authenticator->isAuthorized($request)) {
|
||||||
// on the backchannel only it's not much of a problem.
|
return new JsonResponse(['message' => 'Invalid or missing api key'], 403);
|
||||||
$apiKey = $request->getQueryParams()['key'] ?? null;
|
|
||||||
|
|
||||||
if (null === $apiKey) {
|
|
||||||
return new JsonResponse(['message' => 'No api key provided'], 403);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$productCode = $request->getQueryParams()['product'] ?? null;
|
$productCode = $request->getQueryParams()['product'] ?? null;
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ productImportSftpHostKey =
|
|||||||
# cat=SftpImport; type=int+; label=SFTP connection timeout in seconds
|
# cat=SftpImport; type=int+; label=SFTP connection timeout in seconds
|
||||||
productImportSftpTimeout = 15
|
productImportSftpTimeout = 15
|
||||||
|
|
||||||
# cat=ContentFeed; type=string; label=API key for the CMS backchannel endpoints (chatbot content feed, CMS index); sent as X-Api-Key. Empty denies every request.
|
# cat=ContentFeed; type=string; label=API key for the CMS backchannel endpoints used by MyE&P (/api/hotel, /api/product, /api/content/*); sent as X-Api-Key or ?key=. Empty denies every request.
|
||||||
cmsApiKey =
|
cmsApiKey =
|
||||||
|
|
||||||
# cat=ContentFeed; type=boolean; label=Serve the chatbot content feed (off: all feed endpoints answer 503)
|
# cat=ContentFeed; type=boolean; label=Serve the chatbot content feed (off: all feed endpoints answer 503)
|
||||||
|
|||||||
Reference in new issue
Block a user