Skip to content

Commit 2104b62

Browse files
committed
Remove security on operation level fix
1 parent b6a745c commit 2104b62

File tree

5 files changed

+148
-6
lines changed

5 files changed

+148
-6
lines changed

openapi_core/schema/operations/generators.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,12 +42,16 @@ def generate(self, path_name, path):
4242
tags_list = operation_deref.get('tags', [])
4343
summary = operation_deref.get('summary')
4444
description = operation_deref.get('description')
45-
security_spec = operation_deref.get('security', [])
4645
servers_spec = operation_deref.get('servers', [])
4746

4847
servers = self.servers_generator.generate(servers_spec)
49-
security = self.security_requirements_generator.generate(
50-
security_spec)
48+
49+
security = None
50+
if 'security' in operation_deref:
51+
security_spec = operation_deref.get('security')
52+
security = self.security_requirements_generator.generate(
53+
security_spec)
54+
5155
extensions = self.extensions_generator.generate(operation_deref)
5256

5357
external_docs = None
@@ -67,7 +71,7 @@ def generate(self, path_name, path):
6771
Operation(
6872
http_method, path_name, responses, list(parameters),
6973
summary=summary, description=description,
70-
external_docs=external_docs, security=list(security),
74+
external_docs=external_docs, security=security,
7175
request_body=request_body, deprecated=deprecated,
7276
operation_id=operation_id, tags=list(tags_list),
7377
servers=list(servers), extensions=extensions,

openapi_core/schema/operations/models.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ def __init__(
1818
self.summary = summary
1919
self.description = description
2020
self.external_docs = external_docs
21-
self.security = security
21+
self.security = security and list(security)
2222
self.request_body = request_body
2323
self.deprecated = deprecated
2424
self.operation_id = operation_id

openapi_core/validation/request/validators.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,10 @@ def _validate_body(self, request):
8787
)
8888

8989
def _get_security(self, request, operation):
90-
security = operation.security or self.spec.security
90+
security = self.spec.security
91+
if operation.security is not None:
92+
security = operation.security
93+
9194
if not security:
9295
return {}
9396

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
openapi: "3.0.0"
2+
info:
3+
title: Minimal OpenAPI specification with security override
4+
version: "0.1"
5+
security:
6+
- api_key: []
7+
paths:
8+
/resource/{resId}:
9+
parameters:
10+
- name: resId
11+
in: path
12+
required: true
13+
description: the ID of the resource to retrieve
14+
schema:
15+
type: string
16+
get:
17+
responses:
18+
default:
19+
description: Default security.
20+
post:
21+
security:
22+
- petstore_auth:
23+
- write:pets
24+
- read:pets
25+
responses:
26+
default:
27+
description: Override security.
28+
put:
29+
security: []
30+
responses:
31+
default:
32+
description: Remove security.
33+
components:
34+
securitySchemes:
35+
api_key:
36+
type: apiKey
37+
name: api_key
38+
in: query
39+
petstore_auth:
40+
type: http
41+
scheme: basic
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
from base64 import b64encode
2+
import json
3+
4+
import pytest
5+
from six import text_type
6+
7+
from openapi_core.shortcuts import create_spec
8+
from openapi_core.unmarshalling.schemas.exceptions import InvalidSchemaValue
9+
from openapi_core.validation.exceptions import InvalidSecurity
10+
from openapi_core.validation.response.validators import ResponseValidator
11+
from openapi_core.validation.request.validators import RequestValidator
12+
from openapi_core.testing import MockRequest, MockResponse
13+
14+
15+
@pytest.fixture
16+
def response_validator(spec):
17+
return ResponseValidator(spec)
18+
19+
20+
@pytest.fixture
21+
def request_validator(spec):
22+
return RequestValidator(spec)
23+
24+
25+
@pytest.fixture('class')
26+
def spec(factory):
27+
spec_dict = factory.spec_from_file("data/v3.0/security_override.yaml")
28+
return create_spec(spec_dict)
29+
30+
31+
class TestSecurityOverride(object):
32+
33+
host_url = 'http://petstore.swagger.io'
34+
35+
api_key = '12345'
36+
37+
@property
38+
def api_key_encoded(self):
39+
api_key_bytes = self.api_key.encode('utf8')
40+
api_key_bytes_enc = b64encode(api_key_bytes)
41+
return text_type(api_key_bytes_enc, 'utf8')
42+
43+
def test_default(self, request_validator):
44+
args = {'api_key': self.api_key}
45+
request = MockRequest(
46+
self.host_url, 'get', '/resource/one', args=args)
47+
48+
result = request_validator.validate(request)
49+
50+
assert not result.errors
51+
assert result.security == {
52+
'api_key': self.api_key,
53+
}
54+
55+
def test_default_invalid(self, request_validator):
56+
request = MockRequest(self.host_url, 'get', '/resource/one')
57+
58+
result = request_validator.validate(request)
59+
60+
assert type(result.errors[0]) == InvalidSecurity
61+
assert result.security is None
62+
63+
def test_override(self, request_validator):
64+
authorization = 'Basic ' + self.api_key_encoded
65+
headers = {
66+
'Authorization': authorization,
67+
}
68+
request = MockRequest(
69+
self.host_url, 'post', '/resource/one', headers=headers)
70+
71+
result = request_validator.validate(request)
72+
73+
assert not result.errors
74+
assert result.security == {
75+
'petstore_auth': self.api_key_encoded,
76+
}
77+
78+
def test_override_invalid(self, request_validator):
79+
request = MockRequest(
80+
self.host_url, 'post', '/resource/one')
81+
82+
result = request_validator.validate(request)
83+
84+
assert type(result.errors[0]) == InvalidSecurity
85+
assert result.security is None
86+
87+
def test_remove(self, request_validator):
88+
request = MockRequest(
89+
self.host_url, 'put', '/resource/one')
90+
91+
result = request_validator.validate(request)
92+
93+
assert not result.errors
94+
assert result.security == {}

0 commit comments

Comments
 (0)