Skip to content
This repository has been archived by the owner on Jun 23, 2021. It is now read-only.

Commit

Permalink
Merge fa0ad87 into 5d5077f
Browse files Browse the repository at this point in the history
  • Loading branch information
bertramakers committed Nov 26, 2019
2 parents 5d5077f + fa0ad87 commit d8eb10a
Show file tree
Hide file tree
Showing 6 changed files with 212 additions and 13 deletions.
112 changes: 112 additions & 0 deletions app/ApiGuardServiceProvider.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
<?php

declare(strict_types=1);

namespace CultuurNet\UDB3\UiTPASService;

use CultuurNet\UDB3\ApiGuard\ApiKey\Reader\CompositeApiKeyReader;
use CultuurNet\UDB3\ApiGuard\ApiKey\Reader\CustomHeaderApiKeyReader;
use CultuurNet\UDB3\ApiGuard\ApiKey\Reader\QueryParameterApiKeyReader;
use CultuurNet\UDB3\ApiGuard\Consumer\ConsumerInterface;
use CultuurNet\UDB3\ApiGuard\Consumer\ConsumerReadRepositoryInterface;
use CultuurNet\UDB3\ApiGuard\Consumer\InMemoryConsumerRepository;
use CultuurNet\UDB3\ApiGuard\Consumer\Specification\ConsumerIsInPermissionGroup;
use CultuurNet\UDB3\ApiGuard\CultureFeed\CultureFeedApiKeyAuthenticator;
use CultuurNet\UDB3\ApiGuard\Request\ApiKeyRequestAuthenticator;
use CultuurNet\UDB3\ApiGuard\Request\RequestAuthenticationException;
use Silex\Application;
use Silex\ServiceProviderInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\Core\Authorization\AuthorizationChecker;
use Symfony\Component\Security\Core\Exception\AuthenticationCredentialsNotFoundException;
use ValueObjects\StringLiteral\StringLiteral;

final class ApiGuardServiceProvider implements ServiceProviderInterface
{
public function register(Application $app)
{
$app['auth.api_key_reader'] = $app->share(
function () {
$queryReader = new QueryParameterApiKeyReader('apiKey');
$headerReader = new CustomHeaderApiKeyReader('X-Api-Key');

return new CompositeApiKeyReader(
$queryReader,
$headerReader
);
}
);

$app['auth.consumer_repository'] = $app->share(
function (Application $app) {
return new InMemoryConsumerRepository();
}
);

$app['auth.api_key_authenticator'] = $app->share(
function (Application $app) {
return new CultureFeedApiKeyAuthenticator(
$app['culturefeed'],
$app['auth.consumer_repository']
);
}
);

$app['auth.request_authenticator'] = $app->share(
function (Application $app) {
return new ApiKeyRequestAuthenticator(
$app['auth.api_key_reader'],
$app['auth.api_key_authenticator']
);
}
);

$app->before(
function (Request $request, Application $app) {
if (isset($app['config']['disable_api_key_check']) && $app['config']['disable_api_key_check'] === true) {
return;
}

/** @var AuthorizationChecker $security */
$security = $app['security.authorization_checker'];
/** @var ApiKeyRequestAuthenticator $apiKeyAuthenticator */
$apiKeyAuthenticator = $app['auth.request_authenticator'];

// Also store the ApiKey for later use in the impersonator.
$app['auth.api_key'] = $app['auth.api_key_reader']->read($request);

try {
if (!$security->isGranted('IS_AUTHENTICATED_FULLY')) {
// The request is not authenticated so we don't need to do additional checks since the
// firewall will return an unauthorized error response.
return;
}
} catch (AuthenticationCredentialsNotFoundException $exception) {
// The request is for a public URL so we can skip any checks.
return;
}

$apiKeyAuthenticator->authenticate($request);

// Check that the API consumer linked to the API key has the required permission to use EntryAPI.
$permissionCheck = new ConsumerIsInPermissionGroup(
new StringLiteral((string) $app['config']['api_key']['group_id'])
);

/* @var ConsumerReadRepositoryInterface $consumerRepository */
$consumerRepository = $app['auth.consumer_repository'];
/** @var ConsumerInterface $consumer */
$consumer = $consumerRepository->getConsumer($app['auth.api_key']);

if (!$permissionCheck->satisfiedBy($consumer)) {
throw new RequestAuthenticationException('Given API key is not authorized to use EntryAPI.');
}
},
Application::LATE_EVENT
);
}

public function boot(Application $app)
{
}
}
38 changes: 38 additions & 0 deletions app/CultureFeedServiceProvider.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<?php

declare(strict_types=1);

namespace CultuurNet\UDB3\UiTPASService;

use CultureFeed;
use CultureFeed_DefaultOAuthClient;
use Silex\Application;
use Silex\ServiceProviderInterface;

final class CultureFeedServiceProvider implements ServiceProviderInterface
{
public function register(Application $app)
{
$app['culturefeed'] = $app::share(
function (Application $app) {
$oauthClient = new CultureFeed_DefaultOAuthClient(
$app['config']['uitid']['consumer']['key'],
$app['config']['uitid']['consumer']['secret']
);
$oauthClient->setEndpoint($app['config']['uitid']['base_url']);
return new CultureFeed($oauthClient);
}
);

$app['culturefeed_uitpas_client'] = $app::share(
function (Application $app) {
return $app['culturefeed']->uitpas();
}
);
}

public function boot(Application $app)
{
}

}
13 changes: 2 additions & 11 deletions bootstrap.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<?php

use CultuurNet\SymfonySecurityJwt\Authentication\JwtUserToken;
use CultuurNet\UDB3\UiTPASService\CultureFeedServiceProvider;
use DerAlex\Silex\YamlConfigServiceProvider;
use JDesrosiers\Silex\Provider\CorsServiceProvider;
use Lcobucci\JWT\Token as Jwt;
Expand Down Expand Up @@ -66,16 +67,6 @@ function (Application $app) {
}
);

$app['culturefeed_uitpas_client'] = $app::share(
function (Application $app) {
$oauthClient = new CultureFeed_DefaultOAuthClient(
$app['config']['uitid']['consumer']['key'],
$app['config']['uitid']['consumer']['secret']
);
$oauthClient->setEndpoint($app['config']['uitid']['base_url']);
$cf = new CultureFeed($oauthClient);
return $cf->uitpas();
}
);
$app->register(new CultureFeedServiceProvider());

return $app;
3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@
"jdesrosiers/silex-cors-provider": "~0.1.4",
"knplabs/console-service-provider": "~1.0",
"monolog/monolog": "~1.11",
"silex/silex": "~1.3"
"silex/silex": "~1.3",
"cultuurnet/udb3-api-guard": "~0.1"
},
"require-dev": {
"phpunit/phpunit": "~5.7",
Expand Down
53 changes: 52 additions & 1 deletion composer.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions web/index.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
use CultuurNet\SymfonySecurityJwt\Authentication\JwtAuthenticationEntryPoint;
use CultuurNet\UDB3\HttpFoundation\RequestMatcher\AnyOfRequestMatcher;
use CultuurNet\UDB3\HttpFoundation\RequestMatcher\PreflightRequestMatcher;
use CultuurNet\UDB3\UiTPASService\ApiGuardServiceProvider;
use CultuurNet\UDB3\UiTPASService\Controller\EventControllerProvider;
use CultuurNet\UDB3\UiTPASService\Controller\OrganizerControllerProvider;
use CultuurNet\UDB3\UiTPASService\ErrorHandlerProvider;
Expand All @@ -23,6 +24,11 @@
*/
$app->register(new ServiceControllerServiceProvider());

/**
* Check api keys for requests.
*/
$app->register(new ApiGuardServiceProvider());

/**
* Handle errors by returning an API problem response.
*/
Expand Down

0 comments on commit d8eb10a

Please sign in to comment.