From 9545a0ce52b699a5e5813e23cc512fc6bb86a3e3 Mon Sep 17 00:00:00 2001 From: Jack Cutting Date: Wed, 26 Jan 2022 17:33:35 +0000 Subject: [PATCH] Allow security policies to be removed using the Security annotation by passing it a name of null. --- Describer/OpenApiPhpDescriber.php | 7 +++ Resources/doc/security.rst | 43 +++++++++++++++++++ .../Functional/Controller/ApiController80.php | 10 +++++ .../Functional/Controller/ApiController81.php | 8 ++++ Tests/Functional/FunctionalTest.php | 18 ++++++++ 5 files changed, 86 insertions(+) create mode 100644 Resources/doc/security.rst diff --git a/Describer/OpenApiPhpDescriber.php b/Describer/OpenApiPhpDescriber.php index 1445da4..1e303e7 100644 --- a/Describer/OpenApiPhpDescriber.php +++ b/Describer/OpenApiPhpDescriber.php @@ -109,6 +109,13 @@ final class OpenApiPhpDescriber if ($annotation instanceof Security) { $annotation->validate(); + + if (null === $annotation->name) { + $mergeProperties->security = []; + + continue; + } + $mergeProperties->security[] = [$annotation->name => $annotation->scopes]; continue; diff --git a/Resources/doc/security.rst b/Resources/doc/security.rst new file mode 100644 index 0000000..1cecc8c --- /dev/null +++ b/Resources/doc/security.rst @@ -0,0 +1,43 @@ +Security +======== + +A default security policy can be added in ``nelmio_api_doc.documentation.security`` + +.. code-block:: yaml + + nelmio_api_doc: + documentation: + components: + securitySchemes: + Bearer: + type: http + scheme: bearer + ApiKeyAuth: + type: apiKey + in: header + name: X-API-Key + security: + Bearer: [] + +This will add the Bearer security policy to all registered paths. + +Overriding Specific Paths +------------------------- + +The security policy can be overriden for a path using the ``@Security`` annotation. + +.. code-block:: php + + /** + * @Security(name="ApiKeyAuth") + */ + +Notice at the bottom of the docblock is a ``@Security`` annotation with a name of `ApiKeyAuth`. This will override the global security policy to only accept the ``ApiKeyAuth`` policy for this path. + +You can also completely remove security from a path by providing ``@Security`` with a name of ``null``. + +.. code-block:: php + + /** + * @Security(name=null) + */ \ No newline at end of file diff --git a/Tests/Functional/Controller/ApiController80.php b/Tests/Functional/Controller/ApiController80.php index 64b4101..6e4842b 100644 --- a/Tests/Functional/Controller/ApiController80.php +++ b/Tests/Functional/Controller/ApiController80.php @@ -164,6 +164,16 @@ class ApiController80 { } + /** + * @Route("/securityOverride") + * @OA\Response(response="201", description="") + * @Security(name="api_key") + * @Security(name=null) + */ + public function securityActionOverride() + { + } + /** * @Route("/swagger/symfonyConstraints", methods={"GET"}) * @OA\Response( diff --git a/Tests/Functional/Controller/ApiController81.php b/Tests/Functional/Controller/ApiController81.php index f1c615a..d4195f5 100644 --- a/Tests/Functional/Controller/ApiController81.php +++ b/Tests/Functional/Controller/ApiController81.php @@ -50,4 +50,12 @@ class ApiController81 extends ApiController80 public function securityActionAttributes() { } + + #[Route('/security_override_attributes')] + #[OA\Response(response: '201', description: '')] + #[Security(name: 'api_key')] + #[Security(name: null)] + public function securityOverrideActionAttributes() + { + } } diff --git a/Tests/Functional/FunctionalTest.php b/Tests/Functional/FunctionalTest.php index 27c4322..fb3bd67 100644 --- a/Tests/Functional/FunctionalTest.php +++ b/Tests/Functional/FunctionalTest.php @@ -369,6 +369,24 @@ class FunctionalTest extends WebTestCase } } + /** + * @dataProvider provideSecurityOverrideRoute + */ + public function testSecurityOverrideAction(string $route) + { + $operation = $this->getOperation($route, 'get'); + $this->assertEquals([], $operation->security); + } + + public function provideSecurityOverrideRoute(): iterable + { + yield 'Annotations' => ['/api/securityOverride']; + + if (\PHP_VERSION_ID >= 80100) { + yield 'Attributes' => ['/api/security_override_attributes']; + } + } + public function testClassSecurityAction() { $operation = $this->getOperation('/api/security/class', 'get');