Skip to content

Commit 4ae5a08

Browse files
committed
Security HTTP scheme type support
1 parent d915f23 commit 4ae5a08

File tree

5 files changed

+44
-13
lines changed

5 files changed

+44
-13
lines changed

openapi_core/schema/security_schemes/enums.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,9 @@ class ApiKeyLocation(Enum):
1919
@classmethod
2020
def has_value(cls, value):
2121
return (any(value == item.value for item in cls))
22+
23+
24+
class HttpAuthScheme(Enum):
25+
26+
BASIC = 'basic'
27+
BEARER = 'bearer'

openapi_core/schema/security_schemes/models.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
"""OpenAPI core security schemes models module"""
22
from openapi_core.schema.security_schemes.enums import (
3-
SecuritySchemeType, ApiKeyLocation,
3+
SecuritySchemeType, ApiKeyLocation, HttpAuthScheme,
44
)
55

66

@@ -16,7 +16,7 @@ def __init__(
1616
self.description = description
1717
self.name = name
1818
self.apikey_in = apikey_in and ApiKeyLocation(apikey_in)
19-
self.scheme = scheme
19+
self.scheme = scheme and HttpAuthScheme(scheme)
2020
self.bearer_format = bearer_format
2121
self.flows = flows
2222
self.open_id_connect_url = open_id_connect_url

openapi_core/validation/request/validators.py

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
"""OpenAPI core validation request validators module"""
2+
import base64
3+
import binascii
24
from itertools import chain
35
from six import iteritems
46
import warnings
@@ -103,7 +105,7 @@ def _get_operation(self, request):
103105
def _get_security(self, request, operation):
104106
security = operation.security or self.spec.security
105107
if not security:
106-
return
108+
return {}
107109

108110
for security_requirement in security:
109111
data = {
@@ -113,6 +115,8 @@ def _get_security(self, request, operation):
113115
if all(value for value in data.values()):
114116
return data
115117

118+
return {}
119+
116120
def _get_parameters(self, request, params):
117121
errors = []
118122
seen = set()
@@ -195,6 +199,22 @@ def _get_security_value(self, scheme_name, request):
195199
if scheme.type == SecuritySchemeType.API_KEY:
196200
source = getattr(request.parameters, scheme.apikey_in.value)
197201
return source.get(scheme.name)
202+
elif scheme.type == SecuritySchemeType.HTTP:
203+
auth_header = request.parameters.header.get('Authorization')
204+
try:
205+
auth_type, encoded_credentials = auth_header.split(' ', 1)
206+
except ValueError:
207+
raise ValueError('Could not parse authorization header.')
208+
209+
if auth_type.lower() != scheme.scheme.value:
210+
raise ValueError(
211+
'Unknown authorization method %s' % auth_type)
212+
try:
213+
return base64.b64decode(
214+
encoded_credentials.encode('ascii'), validate=True
215+
).decode('latin1')
216+
except binascii.Error:
217+
raise ValueError('Invalid base64 encoding.')
198218

199219
warnings.warn("Only api key security scheme type supported")
200220

tests/integration/data/v3.0/petstore.yaml

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -75,10 +75,6 @@ paths:
7575
externalDocs:
7676
url: https://example.com
7777
description: Find more info here
78-
security:
79-
- petstore_auth:
80-
- write:pets
81-
- read:pets
8278
servers:
8379
- url: https://development.gigantic-server.com/v1
8480
description: Development server
@@ -128,6 +124,10 @@ paths:
128124
schema:
129125
type: integer
130126
format: int64
127+
security:
128+
- petstore_auth:
129+
- write:pets
130+
- read:pets
131131
responses:
132132
'200':
133133
description: Expected response to a valid request
@@ -371,6 +371,5 @@ components:
371371
name: api_key
372372
in: query
373373
petstore_auth:
374-
type: apiKey
375-
name: api_key
376-
in: header
374+
type: http
375+
scheme: basic

tests/integration/validation/test_validators.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -235,9 +235,7 @@ def test_post_pets(self, validator, spec_dict):
235235
'user': 123,
236236
},
237237
)
238-
assert result.security == {
239-
'petstore_auth': self.api_key_encoded,
240-
}
238+
assert result.security == {}
241239

242240
schemas = spec_dict['components']['schemas']
243241
pet_model = schemas['PetCreate']['x-model']
@@ -251,9 +249,14 @@ def test_post_pets(self, validator, spec_dict):
251249
assert result.body.address.city == pet_city
252250

253251
def test_get_pet(self, validator):
252+
authorization = 'Basic ' + self.api_key_encoded
253+
headers = {
254+
'Authorization': authorization,
255+
}
254256
request = MockRequest(
255257
self.host_url, 'get', '/v1/pets/1',
256258
path_pattern='/v1/pets/{petId}', view_args={'petId': '1'},
259+
headers=headers,
257260
)
258261

259262
result = validator.validate(request)
@@ -265,6 +268,9 @@ def test_get_pet(self, validator):
265268
'petId': 1,
266269
},
267270
)
271+
assert result.security == {
272+
'petstore_auth': self.api_key,
273+
}
268274

269275

270276
class TestPathItemParamsValidator(object):

0 commit comments

Comments
 (0)