Merge pull request #284 from p1c2u/fix/remove-security-fix

Remove security on operation level fix
This commit is contained in:
A 2021-02-02 13:24:34 +00:00 committed by GitHub
commit f2b5bbe1f3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 148 additions and 13 deletions

View file

@ -42,12 +42,16 @@ class OperationsGenerator(object):
tags_list = operation_deref.get('tags', []) tags_list = operation_deref.get('tags', [])
summary = operation_deref.get('summary') summary = operation_deref.get('summary')
description = operation_deref.get('description') description = operation_deref.get('description')
security_spec = operation_deref.get('security', [])
servers_spec = operation_deref.get('servers', []) servers_spec = operation_deref.get('servers', [])
servers = self.servers_generator.generate(servers_spec) servers = self.servers_generator.generate(servers_spec)
security = self.security_requirements_generator.generate(
security_spec) security = None
if 'security' in operation_deref:
security_spec = operation_deref.get('security')
security = self.security_requirements_generator.generate(
security_spec)
extensions = self.extensions_generator.generate(operation_deref) extensions = self.extensions_generator.generate(operation_deref)
external_docs = None external_docs = None
@ -67,7 +71,7 @@ class OperationsGenerator(object):
Operation( Operation(
http_method, path_name, responses, list(parameters), http_method, path_name, responses, list(parameters),
summary=summary, description=description, summary=summary, description=description,
external_docs=external_docs, security=list(security), external_docs=external_docs, security=security,
request_body=request_body, deprecated=deprecated, request_body=request_body, deprecated=deprecated,
operation_id=operation_id, tags=list(tags_list), operation_id=operation_id, tags=list(tags_list),
servers=list(servers), extensions=extensions, servers=list(servers), extensions=extensions,

View file

@ -18,7 +18,7 @@ class Operation(object):
self.summary = summary self.summary = summary
self.description = description self.description = description
self.external_docs = external_docs self.external_docs = external_docs
self.security = security self.security = security and list(security)
self.request_body = request_body self.request_body = request_body
self.deprecated = deprecated self.deprecated = deprecated
self.operation_id = operation_id self.operation_id = operation_id

View file

@ -87,7 +87,10 @@ class RequestValidator(BaseValidator):
) )
def _get_security(self, request, operation): def _get_security(self, request, operation):
security = operation.security or self.spec.security security = self.spec.security
if operation.security is not None:
security = operation.security
if not security: if not security:
return {} return {}

View file

@ -0,0 +1,41 @@
openapi: "3.0.0"
info:
title: Minimal OpenAPI specification with security override
version: "0.1"
security:
- api_key: []
paths:
/resource/{resId}:
parameters:
- name: resId
in: path
required: true
description: the ID of the resource to retrieve
schema:
type: string
get:
responses:
default:
description: Default security.
post:
security:
- petstore_auth:
- write:pets
- read:pets
responses:
default:
description: Override security.
put:
security: []
responses:
default:
description: Remove security.
components:
securitySchemes:
api_key:
type: apiKey
name: api_key
in: query
petstore_auth:
type: http
scheme: basic

View file

@ -152,14 +152,15 @@ class TestPetstore(object):
assert variable.default == variable_spec['default'] assert variable.default == variable_spec['default']
assert variable.enum == variable_spec.get('enum') assert variable.enum == variable_spec.get('enum')
security_spec = operation_spec.get('security', []) security_spec = operation_spec.get('security')
for idx, security_req in enumerate(operation.security): if security_spec is not None:
assert type(security_req) == SecurityRequirement for idx, security_req in enumerate(operation.security):
assert type(security_req) == SecurityRequirement
security_req_spec = security_spec[idx] security_req_spec = security_spec[idx]
for scheme_name in security_req: for scheme_name in security_req:
security_req[scheme_name] == security_req_spec[ security_req[scheme_name] == security_req_spec[
scheme_name] scheme_name]
responses_spec = operation_spec.get('responses') responses_spec = operation_spec.get('responses')

View file

@ -0,0 +1,86 @@
from base64 import b64encode
import pytest
from six import text_type
from openapi_core.shortcuts import create_spec
from openapi_core.validation.exceptions import InvalidSecurity
from openapi_core.validation.request.validators import RequestValidator
from openapi_core.testing import MockRequest
@pytest.fixture
def request_validator(spec):
return RequestValidator(spec)
@pytest.fixture('class')
def spec(factory):
spec_dict = factory.spec_from_file("data/v3.0/security_override.yaml")
return create_spec(spec_dict)
class TestSecurityOverride(object):
host_url = 'http://petstore.swagger.io'
api_key = '12345'
@property
def api_key_encoded(self):
api_key_bytes = self.api_key.encode('utf8')
api_key_bytes_enc = b64encode(api_key_bytes)
return text_type(api_key_bytes_enc, 'utf8')
def test_default(self, request_validator):
args = {'api_key': self.api_key}
request = MockRequest(
self.host_url, 'get', '/resource/one', args=args)
result = request_validator.validate(request)
assert not result.errors
assert result.security == {
'api_key': self.api_key,
}
def test_default_invalid(self, request_validator):
request = MockRequest(self.host_url, 'get', '/resource/one')
result = request_validator.validate(request)
assert type(result.errors[0]) == InvalidSecurity
assert result.security is None
def test_override(self, request_validator):
authorization = 'Basic ' + self.api_key_encoded
headers = {
'Authorization': authorization,
}
request = MockRequest(
self.host_url, 'post', '/resource/one', headers=headers)
result = request_validator.validate(request)
assert not result.errors
assert result.security == {
'petstore_auth': self.api_key_encoded,
}
def test_override_invalid(self, request_validator):
request = MockRequest(
self.host_url, 'post', '/resource/one')
result = request_validator.validate(request)
assert type(result.errors[0]) == InvalidSecurity
assert result.security is None
def test_remove(self, request_validator):
request = MockRequest(
self.host_url, 'put', '/resource/one')
result = request_validator.validate(request)
assert not result.errors
assert result.security == {}