From eac492187ecc4aef7ec219ac8be0b824c51339b6 Mon Sep 17 00:00:00 2001 From: Christoph Reiter <reiter.christoph@gmail.com> Date: Thu, 25 Feb 2021 11:04:09 +0100 Subject: [PATCH] Disable auth by default and add more examples tests The core bundle no longer requires auth by default which means all API endpoints can be accessed without any token now. This adds one custom controlle which requires auth as an example. Also adds some basic tests for all the added endpoints. --- composer.json | 7 +- composer.lock | 246 +++++++++++++++++++++++++++-- phpunit.xml.dist | 2 + src/Controller/LoggedInOnly.php | 19 +++ src/Entity/Place.php | 10 +- src/Resources/config/services.yaml | 5 + tests/ApiTest.php | 40 +++++ tests/Kernel.php | 46 ++++++ 8 files changed, 362 insertions(+), 13 deletions(-) create mode 100644 src/Controller/LoggedInOnly.php create mode 100644 tests/ApiTest.php create mode 100644 tests/Kernel.php diff --git a/composer.json b/composer.json index 06498fa..c6872f5 100644 --- a/composer.json +++ b/composer.json @@ -6,12 +6,15 @@ "php": "^7.3", "api-platform/core": "^2.5", "symfony/framework-bundle": "^4.1.12", - "dbp/api-core-bundle": "dev-main" + "dbp/api-core-bundle": "dev-main", + "ext-json": "*" }, "require-dev": { "friendsofphp/php-cs-fixer": "^2.16", "phpstan/phpstan": "^0.12.33", "phpstan/phpstan-phpunit": "^0.12.13", + "symfony/browser-kit": "^4.4", + "symfony/http-client": "^4.4", "symfony/phpunit-bridge": "^4.4", "vimeo/psalm": "^4.2.1" }, @@ -64,4 +67,4 @@ "@php vendor/bin/simple-phpunit --coverage-html _coverage" ] } -} \ No newline at end of file +} diff --git a/composer.lock b/composer.lock index 123b7ec..7b9868f 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "aacafd2d2227e4937544cb12b9111f79", + "content-hash": "7042f009a8911b77ab5f7b5e030dae86", "packages": [ { "name": "api-platform/core", @@ -224,7 +224,7 @@ "source": { "type": "git", "url": "git@gitlab.tugraz.at:dbp/middleware/dbp-api/api-core-bundle.git", - "reference": "db2c221338c234b762192da66bf9d9f33b4e2662" + "reference": "3d6767a82ed493a37bd7763e5cfb34e2dac1b1a7" }, "require": { "api-platform/core": "<2.6", @@ -300,7 +300,7 @@ "license": [ "AGPL-3.0-or-later" ], - "time": "2021-02-22T10:43:38+00:00" + "time": "2021-02-22T12:56:47+00:00" }, { "name": "doctrine/annotations", @@ -6313,16 +6313,16 @@ }, { "name": "felixfbecker/language-server-protocol", - "version": "v1.5.0", + "version": "1.5.1", "source": { "type": "git", "url": "https://github.com/felixfbecker/php-language-server-protocol.git", - "reference": "85e83cacd2ed573238678c6875f8f0d7ec699541" + "reference": "9d846d1f5cf101deee7a61c8ba7caa0a975cd730" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/felixfbecker/php-language-server-protocol/zipball/85e83cacd2ed573238678c6875f8f0d7ec699541", - "reference": "85e83cacd2ed573238678c6875f8f0d7ec699541", + "url": "https://api.github.com/repos/felixfbecker/php-language-server-protocol/zipball/9d846d1f5cf101deee7a61c8ba7caa0a975cd730", + "reference": "9d846d1f5cf101deee7a61c8ba7caa0a975cd730", "shasum": "" }, "require": { @@ -6363,9 +6363,9 @@ ], "support": { "issues": "https://github.com/felixfbecker/php-language-server-protocol/issues", - "source": "https://github.com/felixfbecker/php-language-server-protocol/tree/v1.5.0" + "source": "https://github.com/felixfbecker/php-language-server-protocol/tree/1.5.1" }, - "time": "2020-10-23T13:55:30+00:00" + "time": "2021-02-22T14:02:09+00:00" }, { "name": "friendsofphp/php-cs-fixer", @@ -6866,6 +6866,77 @@ ], "time": "2020-10-26T13:10:38+00:00" }, + { + "name": "symfony/browser-kit", + "version": "v4.4.19", + "source": { + "type": "git", + "url": "https://github.com/symfony/browser-kit.git", + "reference": "f6f060bdc473c3f3b1f00e2ebdeb3d02eda77f82" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/browser-kit/zipball/f6f060bdc473c3f3b1f00e2ebdeb3d02eda77f82", + "reference": "f6f060bdc473c3f3b1f00e2ebdeb3d02eda77f82", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/dom-crawler": "^3.4|^4.0|^5.0" + }, + "require-dev": { + "symfony/css-selector": "^3.4|^4.0|^5.0", + "symfony/http-client": "^4.3|^5.0", + "symfony/mime": "^4.3|^5.0", + "symfony/process": "^3.4|^4.0|^5.0" + }, + "suggest": { + "symfony/process": "" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\BrowserKit\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Simulates the behavior of a web browser, allowing you to make requests, click on links and submit forms programmatically", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/browser-kit/tree/v4.4.19" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2021-01-27T09:09:26+00:00" + }, { "name": "symfony/console", "version": "v4.4.19", @@ -6955,6 +7026,160 @@ ], "time": "2021-01-27T09:09:26+00:00" }, + { + "name": "symfony/dom-crawler", + "version": "v5.2.3", + "source": { + "type": "git", + "url": "https://github.com/symfony/dom-crawler.git", + "reference": "5d89ceb53ec65e1973a555072fac8ed5ecad3384" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/5d89ceb53ec65e1973a555072fac8ed5ecad3384", + "reference": "5d89ceb53ec65e1973a555072fac8ed5ecad3384", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-mbstring": "~1.0", + "symfony/polyfill-php80": "^1.15" + }, + "conflict": { + "masterminds/html5": "<2.6" + }, + "require-dev": { + "masterminds/html5": "^2.6", + "symfony/css-selector": "^4.4|^5.0" + }, + "suggest": { + "symfony/css-selector": "" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\DomCrawler\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Eases DOM navigation for HTML and XML documents", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/dom-crawler/tree/v5.2.3" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2021-01-27T10:01:46+00:00" + }, + { + "name": "symfony/http-client", + "version": "v4.4.19", + "source": { + "type": "git", + "url": "https://github.com/symfony/http-client.git", + "reference": "d8df50fe9229576b254c6822eb5cfff36c02c967" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/http-client/zipball/d8df50fe9229576b254c6822eb5cfff36c02c967", + "reference": "d8df50fe9229576b254c6822eb5cfff36c02c967", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "psr/log": "^1.0", + "symfony/http-client-contracts": "^1.1.10|^2", + "symfony/polyfill-php73": "^1.11", + "symfony/service-contracts": "^1.0|^2" + }, + "provide": { + "php-http/async-client-implementation": "*", + "php-http/client-implementation": "*", + "psr/http-client-implementation": "1.0", + "symfony/http-client-implementation": "1.1" + }, + "require-dev": { + "guzzlehttp/promises": "^1.4", + "nyholm/psr7": "^1.0", + "php-http/httplug": "^1.0|^2.0", + "psr/http-client": "^1.0", + "symfony/dependency-injection": "^4.3|^5.0", + "symfony/http-kernel": "^4.4.13", + "symfony/process": "^4.2|^5.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\HttpClient\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides powerful methods to fetch HTTP resources synchronously or asynchronously", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/http-client/tree/v4.4.19" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2021-01-27T09:09:26+00:00" + }, { "name": "symfony/options-resolver", "version": "v5.2.3", @@ -7538,7 +7763,8 @@ "prefer-stable": false, "prefer-lowest": false, "platform": { - "php": "^7.3" + "php": "^7.3", + "ext-json": "*" }, "platform-dev": [], "platform-overrides": { diff --git a/phpunit.xml.dist b/phpunit.xml.dist index d908cdd..c8117a0 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -13,6 +13,8 @@ <server name="SHELL_VERBOSITY" value="-1"/> <server name="SYMFONY_PHPUNIT_REMOVE" value=""/> <server name="SYMFONY_PHPUNIT_VERSION" value="9"/> + <server name="SYMFONY_DEPRECATIONS_HELPER" value="weak"/> + <server name="KERNEL_CLASS" value="DBP\API\StarterBundle\Tests\Kernel"/> </php> <testsuites> <testsuite name="Project Test Suite"> diff --git a/src/Controller/LoggedInOnly.php b/src/Controller/LoggedInOnly.php new file mode 100644 index 0000000..18b5785 --- /dev/null +++ b/src/Controller/LoggedInOnly.php @@ -0,0 +1,19 @@ +<?php + +declare(strict_types=1); + +namespace DBP\API\StarterBundle\Controller; + +use DBP\API\StarterBundle\Entity\Place; +use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; +use Symfony\Component\HttpFoundation\Request; + +class LoggedInOnly extends AbstractController +{ + public function __invoke(Place $data, Request $request): Place + { + $this->denyAccessUnlessGranted('IS_AUTHENTICATED_FULLY'); + + return $data; + } +} diff --git a/src/Entity/Place.php b/src/Entity/Place.php index 8f981fd..74866c4 100644 --- a/src/Entity/Place.php +++ b/src/Entity/Place.php @@ -6,6 +6,7 @@ namespace DBP\API\StarterBundle\Entity; use ApiPlatform\Core\Annotation\ApiProperty; use ApiPlatform\Core\Annotation\ApiResource; +use DBP\API\StarterBundle\Controller\LoggedInOnly; use Symfony\Component\Serializer\Annotation\Groups; /** @@ -16,7 +17,14 @@ use Symfony\Component\Serializer\Annotation\Groups; * itemOperations={ * "get", * "put", - * "delete" + * "delete", + * "loggedin_only" = { + * "security" = "is_granted('IS_AUTHENTICATED_FULLY')", + * "method" = "GET", + * "path" = "/places/{id}/loggedin-only", + * "controller" = LoggedInOnly::class, + * "openapi_context" = {"summary" = "Only works when logged in."}, + * } * }, * iri="https://schema.org/Place", * normalizationContext={ diff --git a/src/Resources/config/services.yaml b/src/Resources/config/services.yaml index 2eec657..9916eaf 100644 --- a/src/Resources/config/services.yaml +++ b/src/Resources/config/services.yaml @@ -3,6 +3,11 @@ services: autowire: true autoconfigure: true + DBP\API\StarterBundle\Controller\: + resource: '../../Controller' + tags: ['controller.service_arguments'] + autowire: true + DBP\API\StarterBundle\DataProvider\PlaceCollectionDataProvider: tags: [{ name: 'api_platform.collection_data_provider'}] autowire: true diff --git a/tests/ApiTest.php b/tests/ApiTest.php new file mode 100644 index 0000000..1fc411a --- /dev/null +++ b/tests/ApiTest.php @@ -0,0 +1,40 @@ +<?php + +declare(strict_types=1); + +namespace DBP\API\StarterBundle\Tests; + +use ApiPlatform\Core\Bridge\Symfony\Bundle\Test\ApiTestCase; +use Symfony\Component\HttpFoundation\Response; + +class ApiTest extends ApiTestCase +{ + public function testBasics() + { + $client = self::createClient(); + $response = $client->request('GET', '/places'); + $this->assertSame(Response::HTTP_OK, $response->getStatusCode()); + + $response = $client->request('GET', '/places/graz'); + $this->assertSame(Response::HTTP_OK, $response->getStatusCode()); + + $response = $client->request('DELETE', '/places/graz'); + $this->assertSame(Response::HTTP_NO_CONTENT, $response->getStatusCode()); + + $response = $client->request('PUT', '/places/graz', [ + 'headers' => [ + 'Content-Type' => 'application/json', + ], + 'body' => json_encode(['name' => 'foo']), + ]); + $this->assertSame(Response::HTTP_OK, $response->getStatusCode()); + $this->assertSame('foo', json_decode($response->getContent(), true)['name']); + } + + public function testNoAuth() + { + $client = self::createClient(); + $response = $client->request('GET', '/places/graz/loggedin-only'); + $this->assertSame(Response::HTTP_UNAUTHORIZED, $response->getStatusCode()); + } +} diff --git a/tests/Kernel.php b/tests/Kernel.php new file mode 100644 index 0000000..4c9936e --- /dev/null +++ b/tests/Kernel.php @@ -0,0 +1,46 @@ +<?php + +declare(strict_types=1); + +namespace DBP\API\StarterBundle\Tests; + +use ApiPlatform\Core\Bridge\Symfony\Bundle\ApiPlatformBundle; +use DBP\API\CoreBundle\DbpCoreBundle; +use DBP\API\StarterBundle\DbpStarterBundle; +use Nelmio\CorsBundle\NelmioCorsBundle; +use Symfony\Bundle\FrameworkBundle\FrameworkBundle; +use Symfony\Bundle\FrameworkBundle\Kernel\MicroKernelTrait; +use Symfony\Bundle\SecurityBundle\SecurityBundle; +use Symfony\Bundle\TwigBundle\TwigBundle; +use Symfony\Component\Config\Loader\LoaderInterface; +use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\HttpKernel\Kernel as BaseKernel; +use Symfony\Component\Routing\RouteCollectionBuilder; + +class Kernel extends BaseKernel +{ + use MicroKernelTrait; + + public function registerBundles(): iterable + { + yield new FrameworkBundle(); + yield new SecurityBundle(); + yield new TwigBundle(); + yield new NelmioCorsBundle(); + yield new ApiPlatformBundle(); + yield new DbpStarterBundle(); + yield new DbpCoreBundle(); + } + + protected function configureRoutes(RouteCollectionBuilder $routes) + { + $routes->import('@DbpCoreBundle/Resources/config/routing.yaml'); + } + + protected function configureContainer(ContainerBuilder $c, LoaderInterface $loader) + { + $c->loadFromExtension('framework', [ + 'test' => true, + ]); + } +} -- GitLab