Skip to content

How to use Security and SecurityRequirement #225

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
e33b410
Create PR
SOHELAHMED7 Feb 5, 2025
e5751c2
Implementation in progress
SOHELAHMED7 Feb 7, 2025
2f65031
In progress...
SOHELAHMED7 Feb 7, 2025
0c532a7
Remove comments
SOHELAHMED7 Feb 11, 2025
2876e4a
Finish the test
SOHELAHMED7 Feb 11, 2025
dc0863c
Changes
SOHELAHMED7 Feb 11, 2025
5186b46
Add `SecurityRequirements` class and more
SOHELAHMED7 Feb 12, 2025
a455e6e
In Progress
SOHELAHMED7 Feb 12, 2025
6fd4971
Apply same changes to other file
SOHELAHMED7 Feb 12, 2025
49f1164
Merge branches 'master' and 'how-to-use-security-and-securityrequirem…
SOHELAHMED7 Mar 14, 2025
b7c0a6d
Revert changes
SOHELAHMED7 Mar 14, 2025
29f5bbb
Change design of SecurityScheme
SOHELAHMED7 Mar 14, 2025
b46de76
Complete the implementation
SOHELAHMED7 Mar 14, 2025
219813f
Fix failing test
SOHELAHMED7 Mar 15, 2025
236a47e
Cleanup and fix issue and complete the implementation
SOHELAHMED7 Mar 15, 2025
55f3e1f
Complete the test
SOHELAHMED7 Mar 15, 2025
23a5377
Covers SecurityRequirements
SOHELAHMED7 Mar 15, 2025
565c183
Put back removed Composer Package
SOHELAHMED7 Mar 15, 2025
c1db324
Fix failing tests
SOHELAHMED7 Mar 15, 2025
c911987
Fix failing tests 2
SOHELAHMED7 Mar 15, 2025
98b3ef3
Fix failing tests 3
SOHELAHMED7 Mar 15, 2025
15ef5f6
Add more assertions in tests and refactor
SOHELAHMED7 Mar 17, 2025
19e68bf
Add more test
SOHELAHMED7 Mar 17, 2025
e8711e1
Resolve TODOs
SOHELAHMED7 Mar 17, 2025
29e7095
Merge branch 'master' of github.com:SOHELAHMED7/php-openapi into how-…
SOHELAHMED7 Apr 25, 2025
2a66059
Remove redundant method call
SOHELAHMED7 Apr 25, 2025
aa73b3d
Remove redundant method call 2
SOHELAHMED7 Apr 29, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ fix-style: php-cs-fixer.phar
$(DOCKER_PHP) vendor/bin/indent --spaces .php_cs.dist
$(DOCKER_PHP) ./php-cs-fixer.phar fix src/ --diff

cli:
docker-compose run --rm php bash

install:
$(DOCKER_PHP) composer install --prefer-dist --no-interaction --no-progress --ansi
$(DOCKER_NODE) yarn install
Expand Down Expand Up @@ -82,4 +85,3 @@ coverage: .php-openapi-covA .php-openapi-covB
grep -rhPo '^class \w+' src/spec/ | awk '{print $$2}' |grep -v '^Type$$' | sort > $@

.PHONY: all check-style fix-style install test lint coverage

3 changes: 1 addition & 2 deletions src/spec/OpenApi.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@

namespace cebe\openapi\spec;

use cebe\openapi\exceptions\TypeErrorException;
use cebe\openapi\SpecBaseObject;

/**
Expand Down Expand Up @@ -38,7 +37,7 @@ protected function attributes(): array
'servers' => [Server::class],
'paths' => Paths::class,
'components' => Components::class,
'security' => [SecurityRequirement::class],
'security' => SecurityRequirements::class,
'tags' => [Tag::class],
'externalDocs' => ExternalDocumentation::class,
];
Expand Down
2 changes: 1 addition & 1 deletion src/spec/Operation.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ protected function attributes(): array
'responses' => Responses::class,
'callbacks' => [Type::STRING, Callback::class],
'deprecated' => Type::BOOLEAN,
'security' => [SecurityRequirement::class],
'security' => SecurityRequirements::class,
'servers' => [Server::class],
];
}
Expand Down
14 changes: 13 additions & 1 deletion src/spec/SecurityRequirement.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,20 @@
use cebe\openapi\SpecBaseObject;

/**
* Lists the required security schemes to execute this operation.
* A required security scheme to execute this operation.
*
* @link https://github.com/OAI/OpenAPI-Specification/blob/3.0.2/versions/3.0.2.md#securityRequirementObject
*
*/
class SecurityRequirement extends SpecBaseObject
{
private $_securityRequirement;
public function __construct(array $data)
{
parent::__construct($data);
$this->_securityRequirement = $data;
}

/**
* @return array array of attributes available in this object.
*/
Expand All @@ -34,4 +41,9 @@ protected function attributes(): array
protected function performValidation()
{
}

public function getSerializableData()
{
return $this->_securityRequirement;
}
}
78 changes: 78 additions & 0 deletions src/spec/SecurityRequirements.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
<?php

/**
* @copyright Copyright (c) 2018 Carsten Brandt <mail@cebe.cc> and contributors
* @license https://github.com/cebe/php-openapi/blob/master/LICENSE
*/

namespace cebe\openapi\spec;

use cebe\openapi\SpecBaseObject;

/**
* Lists the required security schemes to execute this operation.
*
* @link https://github.com/OAI/OpenAPI-Specification/blob/3.0.2/versions/3.0.2.md#securityRequirementObject
*
*/
class SecurityRequirements extends SpecBaseObject
{
private $_securityRequirements;

public function __construct(array $data)
{
parent::__construct($data);

foreach ($data as $index => $value) {
if (is_numeric($index)) { // read
$this->_securityRequirements[array_keys($value)[0]] = new SecurityRequirement(array_values($value)[0]);
} else { // write
$this->_securityRequirements[$index] = $value;
}
}
if ($data === []) {
$this->_securityRequirements = [];
}
}

/**
* @return array array of attributes available in this object.
*/
protected function attributes(): array
{
// this object does not have a fixed set of attribute names
return [];
}

/**
* Perform validation on this object, check data against OpenAPI Specification rules.
*
* Call `addError()` in case of validation errors.
*/
protected function performValidation()
{
}

/**
* {@inheritDoc}
*/
public function getSerializableData()
{
$data = [];
foreach ($this->_securityRequirements ?? [] as $name => $securityRequirement) {
/** @var SecurityRequirement $securityRequirement */
$data[] = [$name => $securityRequirement->getSerializableData()];
}
return $data;
}

public function getRequirement(string $name)
{
return $this->_securityRequirements[$name] ?? null;
}

public function getRequirements()
{
return $this->_securityRequirements;
}
}
114 changes: 112 additions & 2 deletions tests/WriterTest.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
<?php

use cebe\openapi\spec\Components;
use cebe\openapi\spec\Operation;
use cebe\openapi\spec\PathItem;
use cebe\openapi\spec\Response;
use cebe\openapi\spec\Responses;
use cebe\openapi\spec\SecurityRequirement;
use cebe\openapi\spec\SecurityRequirements;
use cebe\openapi\spec\SecurityScheme;

class WriterTest extends \PHPUnit\Framework\TestCase
{
Expand Down Expand Up @@ -137,7 +144,9 @@ public function testWriteEmptySecurityYaml()
public function testWriteEmptySecurityPartJson()
{
$openapi = $this->createOpenAPI([
'security' => [new SecurityRequirement(['Bearer' => []])],
'security' => new SecurityRequirements([
'Bearer' => new SecurityRequirement([])
]),
]);

$json = \cebe\openapi\Writer::writeToJson($openapi);
Expand Down Expand Up @@ -166,7 +175,9 @@ public function testWriteEmptySecurityPartJson()
public function testWriteEmptySecurityPartYaml()
{
$openapi = $this->createOpenAPI([
'security' => [new SecurityRequirement(['Bearer' => []])],
'security' => new SecurityRequirements([
'Bearer' => new SecurityRequirement([])
]),
]);

$yaml = \cebe\openapi\Writer::writeToYaml($openapi);
Expand All @@ -182,6 +193,105 @@ public function testWriteEmptySecurityPartYaml()
-
Bearer: []

YAML
),
$yaml
);
}

public function testSecurityAtPathOperationLevel()
{
$openapi = $this->createOpenAPI([
'components' => new Components([
'securitySchemes' => [
'BearerAuth' => new SecurityScheme([
'type' => 'http',
'scheme' => 'bearer',
'bearerFormat' => 'AuthToken and JWT Format' # optional, arbitrary value for documentation purposes
]),
],
]),
'paths' => [
'/test' => new PathItem([
'get' => new Operation([
'security' => new SecurityRequirements([
'BearerAuth' => new SecurityRequirement([]),
]),
'responses' => new Responses([
200 => new Response(['description' => 'OK']),
])
])
])
]
]);

$yaml = \cebe\openapi\Writer::writeToYaml($openapi);


$this->assertEquals(preg_replace('~\R~', "\n", <<<YAML
openapi: 3.0.0
info:
title: 'Test API'
version: 1.0.0
paths:
/test:
get:
responses:
'200':
description: OK
security:
-
BearerAuth: []
components:
securitySchemes:
BearerAuth:
type: http
scheme: bearer
bearerFormat: 'AuthToken and JWT Format'

YAML
),
$yaml
);
}

public function testSecurityAtGlobalLevel()
{
$openapi = $this->createOpenAPI([
'components' => new Components([
'securitySchemes' => [
'BearerAuth' => new SecurityScheme([
'type' => 'http',
'scheme' => 'bearer',
'bearerFormat' => 'AuthToken and JWT Format' # optional, arbitrary value for documentation purposes
])
],
]),
'security' => new SecurityRequirements([
'BearerAuth' => new SecurityRequirement([])
]),
'paths' => [],
]);

$yaml = \cebe\openapi\Writer::writeToYaml($openapi);


$this->assertEquals(preg_replace('~\R~', "\n", <<<YAML
openapi: 3.0.0
info:
title: 'Test API'
version: 1.0.0
paths: { }
components:
securitySchemes:
BearerAuth:
type: http
scheme: bearer
bearerFormat: 'AuthToken and JWT Format'
security:
-
BearerAuth: []

YAML
),
$yaml
Expand Down
5 changes: 3 additions & 2 deletions tests/spec/OpenApiTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ public function testReadPetStore()
$this->assertInstanceOf(\cebe\openapi\spec\Components::class, $openapi->components);

// security
$this->assertAllInstanceOf(\cebe\openapi\spec\SecurityRequirement::class, $openapi->security);
$this->assertNull($openapi->security); # since it is not present in spec

// tags
$this->assertAllInstanceOf(\cebe\openapi\spec\Tag::class, $openapi->tags);
Expand Down Expand Up @@ -221,7 +221,8 @@ public function testSpecs($openApiFile)
}

// security
$this->assertAllInstanceOf(\cebe\openapi\spec\SecurityRequirement::class, $openapi->security);
$openapi->security !== null && $this->assertInstanceOf(\cebe\openapi\spec\SecurityRequirements::class, $openapi->security);
$openapi->security !== null && $this->assertAllInstanceOf(\cebe\openapi\spec\SecurityRequirement::class, $openapi->security->getRequirements());

// tags
$this->assertAllInstanceOf(\cebe\openapi\spec\Tag::class, $openapi->tags);
Expand Down
9 changes: 5 additions & 4 deletions tests/spec/OperationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -79,10 +79,11 @@ public function testRead()

$this->assertInstanceOf(\cebe\openapi\spec\Responses::class, $operation->responses);

$this->assertCount(1, $operation->security);
$this->assertInstanceOf(\cebe\openapi\spec\SecurityRequirement::class, $operation->security[0]);
$this->assertCount(2, $operation->security[0]->petstore_auth);
$this->assertEquals(['write:pets', 'read:pets'], $operation->security[0]->petstore_auth);
$this->assertCount(1, $operation->security->getRequirements());
$this->assertInstanceOf(\cebe\openapi\spec\SecurityRequirements::class, $operation->security);
$this->assertInstanceOf(\cebe\openapi\spec\SecurityRequirement::class, $operation->security->getRequirement('petstore_auth'));
$this->assertCount(2, $operation->security->getRequirement('petstore_auth')->getSerializableData());
$this->assertEquals(['write:pets', 'read:pets'], $operation->security->getRequirement('petstore_auth')->getSerializableData());

$this->assertInstanceOf(ExternalDocumentation::class, $operation->externalDocs);
$this->assertEquals('Find more info here', $operation->externalDocs->description);
Expand Down
7 changes: 4 additions & 3 deletions tests/spec/SecuritySchemeTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
* @covers \cebe\openapi\spec\OAuthFlows
* @covers \cebe\openapi\spec\OAuthFlow
* @covers \cebe\openapi\spec\SecurityRequirement
* @covers \cebe\openapi\spec\SecurityRequirements
*/
class SecuritySchemeTest extends \PHPUnit\Framework\TestCase
{
Expand Down Expand Up @@ -199,10 +200,10 @@ public function testDefaultSecurity()
YAML
);

$this->assertSame([], $openapi->paths->getPath('/path/one')->post->security);
$this->assertSame([], $openapi->paths->getPath('/path/one')->post->security->getRequirements());
$this->assertSame(null, $openapi->paths->getPath('/path/two')->post->security);

$this->assertCount(1, $openapi->security);
$this->assertSame([], $openapi->security[0]->Bearer);
$this->assertCount(1, $openapi->security->getRequirements());
$this->assertSame([], $openapi->security->getRequirement('Bearer')->getSerializableData());
}
}