Skip to content

Commit e691d93

Browse files
authored
Merge pull request #225 from SOHELAHMED7/how-to-use-security-and-securityrequirement-75
How to use Security and SecurityRequirement
2 parents 4c670b0 + aa73b3d commit e691d93

9 files changed

+220
-16
lines changed

Makefile

+3-1
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,9 @@ fix-style: php-cs-fixer.phar
3737
$(DOCKER_PHP) vendor/bin/indent --spaces .php_cs.dist
3838
$(DOCKER_PHP) ./php-cs-fixer.phar fix src/ --diff
3939

40+
cli:
41+
docker-compose run --rm php bash
42+
4043
install:
4144
$(DOCKER_PHP) composer install --prefer-dist --no-interaction --no-progress --ansi
4245
$(DOCKER_NODE) yarn install
@@ -82,4 +85,3 @@ coverage: .php-openapi-covA .php-openapi-covB
8285
grep -rhPo '^class \w+' src/spec/ | awk '{print $$2}' |grep -v '^Type$$' | sort > $@
8386

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

src/spec/OpenApi.php

+1-2
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77

88
namespace cebe\openapi\spec;
99

10-
use cebe\openapi\exceptions\TypeErrorException;
1110
use cebe\openapi\SpecBaseObject;
1211

1312
/**
@@ -38,7 +37,7 @@ protected function attributes(): array
3837
'servers' => [Server::class],
3938
'paths' => Paths::class,
4039
'components' => Components::class,
41-
'security' => [SecurityRequirement::class],
40+
'security' => SecurityRequirements::class,
4241
'tags' => [Tag::class],
4342
'externalDocs' => ExternalDocumentation::class,
4443
];

src/spec/Operation.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ protected function attributes(): array
4646
'responses' => Responses::class,
4747
'callbacks' => [Type::STRING, Callback::class],
4848
'deprecated' => Type::BOOLEAN,
49-
'security' => [SecurityRequirement::class],
49+
'security' => SecurityRequirements::class,
5050
'servers' => [Server::class],
5151
];
5252
}

src/spec/SecurityRequirement.php

+13-1
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,20 @@
1010
use cebe\openapi\SpecBaseObject;
1111

1212
/**
13-
* Lists the required security schemes to execute this operation.
13+
* A required security scheme to execute this operation.
1414
*
1515
* @link https://github.com/OAI/OpenAPI-Specification/blob/3.0.2/versions/3.0.2.md#securityRequirementObject
1616
*
1717
*/
1818
class SecurityRequirement extends SpecBaseObject
1919
{
20+
private $_securityRequirement;
21+
public function __construct(array $data)
22+
{
23+
parent::__construct($data);
24+
$this->_securityRequirement = $data;
25+
}
26+
2027
/**
2128
* @return array array of attributes available in this object.
2229
*/
@@ -34,4 +41,9 @@ protected function attributes(): array
3441
protected function performValidation()
3542
{
3643
}
44+
45+
public function getSerializableData()
46+
{
47+
return $this->_securityRequirement;
48+
}
3749
}

src/spec/SecurityRequirements.php

+78
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
<?php
2+
3+
/**
4+
* @copyright Copyright (c) 2018 Carsten Brandt <[email protected]> and contributors
5+
* @license https://github.com/cebe/php-openapi/blob/master/LICENSE
6+
*/
7+
8+
namespace cebe\openapi\spec;
9+
10+
use cebe\openapi\SpecBaseObject;
11+
12+
/**
13+
* Lists the required security schemes to execute this operation.
14+
*
15+
* @link https://github.com/OAI/OpenAPI-Specification/blob/3.0.2/versions/3.0.2.md#securityRequirementObject
16+
*
17+
*/
18+
class SecurityRequirements extends SpecBaseObject
19+
{
20+
private $_securityRequirements;
21+
22+
public function __construct(array $data)
23+
{
24+
parent::__construct($data);
25+
26+
foreach ($data as $index => $value) {
27+
if (is_numeric($index)) { // read
28+
$this->_securityRequirements[array_keys($value)[0]] = new SecurityRequirement(array_values($value)[0]);
29+
} else { // write
30+
$this->_securityRequirements[$index] = $value;
31+
}
32+
}
33+
if ($data === []) {
34+
$this->_securityRequirements = [];
35+
}
36+
}
37+
38+
/**
39+
* @return array array of attributes available in this object.
40+
*/
41+
protected function attributes(): array
42+
{
43+
// this object does not have a fixed set of attribute names
44+
return [];
45+
}
46+
47+
/**
48+
* Perform validation on this object, check data against OpenAPI Specification rules.
49+
*
50+
* Call `addError()` in case of validation errors.
51+
*/
52+
protected function performValidation()
53+
{
54+
}
55+
56+
/**
57+
* {@inheritDoc}
58+
*/
59+
public function getSerializableData()
60+
{
61+
$data = [];
62+
foreach ($this->_securityRequirements ?? [] as $name => $securityRequirement) {
63+
/** @var SecurityRequirement $securityRequirement */
64+
$data[] = [$name => $securityRequirement->getSerializableData()];
65+
}
66+
return $data;
67+
}
68+
69+
public function getRequirement(string $name)
70+
{
71+
return $this->_securityRequirements[$name] ?? null;
72+
}
73+
74+
public function getRequirements()
75+
{
76+
return $this->_securityRequirements;
77+
}
78+
}

tests/WriterTest.php

+112-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
11
<?php
22

3+
use cebe\openapi\spec\Components;
4+
use cebe\openapi\spec\Operation;
5+
use cebe\openapi\spec\PathItem;
6+
use cebe\openapi\spec\Response;
7+
use cebe\openapi\spec\Responses;
38
use cebe\openapi\spec\SecurityRequirement;
9+
use cebe\openapi\spec\SecurityRequirements;
10+
use cebe\openapi\spec\SecurityScheme;
411

512
class WriterTest extends \PHPUnit\Framework\TestCase
613
{
@@ -137,7 +144,9 @@ public function testWriteEmptySecurityYaml()
137144
public function testWriteEmptySecurityPartJson()
138145
{
139146
$openapi = $this->createOpenAPI([
140-
'security' => [new SecurityRequirement(['Bearer' => []])],
147+
'security' => new SecurityRequirements([
148+
'Bearer' => new SecurityRequirement([])
149+
]),
141150
]);
142151

143152
$json = \cebe\openapi\Writer::writeToJson($openapi);
@@ -166,7 +175,9 @@ public function testWriteEmptySecurityPartJson()
166175
public function testWriteEmptySecurityPartYaml()
167176
{
168177
$openapi = $this->createOpenAPI([
169-
'security' => [new SecurityRequirement(['Bearer' => []])],
178+
'security' => new SecurityRequirements([
179+
'Bearer' => new SecurityRequirement([])
180+
]),
170181
]);
171182

172183
$yaml = \cebe\openapi\Writer::writeToYaml($openapi);
@@ -182,6 +193,105 @@ public function testWriteEmptySecurityPartYaml()
182193
-
183194
Bearer: []
184195
196+
YAML
197+
),
198+
$yaml
199+
);
200+
}
201+
202+
public function testSecurityAtPathOperationLevel()
203+
{
204+
$openapi = $this->createOpenAPI([
205+
'components' => new Components([
206+
'securitySchemes' => [
207+
'BearerAuth' => new SecurityScheme([
208+
'type' => 'http',
209+
'scheme' => 'bearer',
210+
'bearerFormat' => 'AuthToken and JWT Format' # optional, arbitrary value for documentation purposes
211+
]),
212+
],
213+
]),
214+
'paths' => [
215+
'/test' => new PathItem([
216+
'get' => new Operation([
217+
'security' => new SecurityRequirements([
218+
'BearerAuth' => new SecurityRequirement([]),
219+
]),
220+
'responses' => new Responses([
221+
200 => new Response(['description' => 'OK']),
222+
])
223+
])
224+
])
225+
]
226+
]);
227+
228+
$yaml = \cebe\openapi\Writer::writeToYaml($openapi);
229+
230+
231+
$this->assertEquals(preg_replace('~\R~', "\n", <<<YAML
232+
openapi: 3.0.0
233+
info:
234+
title: 'Test API'
235+
version: 1.0.0
236+
paths:
237+
/test:
238+
get:
239+
responses:
240+
'200':
241+
description: OK
242+
security:
243+
-
244+
BearerAuth: []
245+
components:
246+
securitySchemes:
247+
BearerAuth:
248+
type: http
249+
scheme: bearer
250+
bearerFormat: 'AuthToken and JWT Format'
251+
252+
YAML
253+
),
254+
$yaml
255+
);
256+
}
257+
258+
public function testSecurityAtGlobalLevel()
259+
{
260+
$openapi = $this->createOpenAPI([
261+
'components' => new Components([
262+
'securitySchemes' => [
263+
'BearerAuth' => new SecurityScheme([
264+
'type' => 'http',
265+
'scheme' => 'bearer',
266+
'bearerFormat' => 'AuthToken and JWT Format' # optional, arbitrary value for documentation purposes
267+
])
268+
],
269+
]),
270+
'security' => new SecurityRequirements([
271+
'BearerAuth' => new SecurityRequirement([])
272+
]),
273+
'paths' => [],
274+
]);
275+
276+
$yaml = \cebe\openapi\Writer::writeToYaml($openapi);
277+
278+
279+
$this->assertEquals(preg_replace('~\R~', "\n", <<<YAML
280+
openapi: 3.0.0
281+
info:
282+
title: 'Test API'
283+
version: 1.0.0
284+
paths: { }
285+
components:
286+
securitySchemes:
287+
BearerAuth:
288+
type: http
289+
scheme: bearer
290+
bearerFormat: 'AuthToken and JWT Format'
291+
security:
292+
-
293+
BearerAuth: []
294+
185295
YAML
186296
),
187297
$yaml

tests/spec/OpenApiTest.php

+3-2
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ public function testReadPetStore()
7272
$this->assertInstanceOf(\cebe\openapi\spec\Components::class, $openapi->components);
7373

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

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

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

226227
// tags
227228
$this->assertAllInstanceOf(\cebe\openapi\spec\Tag::class, $openapi->tags);

tests/spec/OperationTest.php

+5-4
Original file line numberDiff line numberDiff line change
@@ -79,10 +79,11 @@ public function testRead()
7979

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

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

8788
$this->assertInstanceOf(ExternalDocumentation::class, $operation->externalDocs);
8889
$this->assertEquals('Find more info here', $operation->externalDocs->description);

tests/spec/SecuritySchemeTest.php

+4-3
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
* @covers \cebe\openapi\spec\OAuthFlows
1212
* @covers \cebe\openapi\spec\OAuthFlow
1313
* @covers \cebe\openapi\spec\SecurityRequirement
14+
* @covers \cebe\openapi\spec\SecurityRequirements
1415
*/
1516
class SecuritySchemeTest extends \PHPUnit\Framework\TestCase
1617
{
@@ -199,10 +200,10 @@ public function testDefaultSecurity()
199200
YAML
200201
);
201202

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

205-
$this->assertCount(1, $openapi->security);
206-
$this->assertSame([], $openapi->security[0]->Bearer);
206+
$this->assertCount(1, $openapi->security->getRequirements());
207+
$this->assertSame([], $openapi->security->getRequirement('Bearer')->getSerializableData());
207208
}
208209
}

0 commit comments

Comments
 (0)