Skip to content

Commit

Permalink
Bugfix/async security check (#1512)
Browse files Browse the repository at this point in the history
* Add failing tests

* Use for else construct
  • Loading branch information
Ruwann committed Apr 16, 2022
1 parent ea45242 commit c71b116
Show file tree
Hide file tree
Showing 11 changed files with 97 additions and 2 deletions.
2 changes: 1 addition & 1 deletion connexion/security/async_security_handler_factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ async def wrapper(request):
except Exception as err:
errors.append(err)

if token_info is cls.no_value:
else:
if errors != []:
cls._raise_most_specific(errors)
else:
Expand Down
2 changes: 1 addition & 1 deletion connexion/security/security_handler_factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -375,7 +375,7 @@ def wrapper(request):
except Exception as err:
errors.append(err)

if token_info is cls.no_value:
else:
if errors != []:
cls._raise_most_specific(errors)
else:
Expand Down
14 changes: 14 additions & 0 deletions tests/aiohttp/test_aiohttp_api_secure.py
Original file line number Diff line number Diff line change
Expand Up @@ -159,3 +159,17 @@ async def test_async_secure(aiohttp_api_spec_dir, aiohttp_client):
response = await app_client.get('/v1.0/async_bearer_auth', headers={'Authorization': bearer_header})
assert response.status == 200
assert (await response.json()) == {"scope": ['myscope'], "uid": 'test-user'}

@pytest.mark.parametrize('spec', ['swagger_secure.yaml', 'openapi_secure.yaml'])
async def test_auth_exception_swagger(oauth_aiohttp_client, aiohttp_api_spec_dir, aiohttp_client, spec):
app = AioHttpApp(__name__, port=5001, specification_dir=aiohttp_api_spec_dir, debug=True)
app.add_api(spec)

app_client = await aiohttp_client(app.app)

response = await app_client.get(
'/v1.0/fail_auth',
headers={'X-API-Key-2': 'foo'}
)
assert response.status == 401
assert response.content_type == 'application/problem+json'
4 changes: 4 additions & 0 deletions tests/api/test_secure_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,10 @@ def test_security(oauth_requests, secure_endpoint_app):
assert response.data == b'"Unauthenticated"\n'
assert response.status_code == 200

# security function throws exception
response = app_client.get('/v1.0/auth-exception', headers={'X-Api-Key': 'foo'})
assert response.status_code == 401


def test_checking_that_client_token_has_all_necessary_scopes(
oauth_requests, secure_endpoint_app):
Expand Down
2 changes: 2 additions & 0 deletions tests/fakeapi/aiohttp_handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,8 @@ async def aiohttp_bearer_auth(token_info):
async def aiohttp_async_bearer_auth(token_info):
return await aiohttp_token_info(token_info)

async def aiohttp_async_auth_exception(token_info):
return await aiohttp_token_info(token_info)

async def get_datetime():
return ConnexionResponse(body={'value': datetime.datetime(2000, 1, 2, 3, 4, 5, 6)})
Expand Down
5 changes: 5 additions & 0 deletions tests/fakeapi/auth.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import asyncio
import json

from connexion.exceptions import OAuthProblem


def fake_basic_auth(username, password, required_scopes=None):
if username == password:
Expand All @@ -25,3 +27,6 @@ async def async_json_auth(token, required_scopes=None, request=None):

async def async_scope_validation(required_scopes, token_scopes, request):
return required_scopes == token_scopes

async def async_auth_exception(token, required_scopes=None, request=None):
raise OAuthProblem
8 changes: 8 additions & 0 deletions tests/fakeapi/hello/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import uuid

from connexion import NoContent, ProblemException, context, request
from connexion.exceptions import OAuthProblem
from flask import jsonify, redirect, send_file


Expand Down Expand Up @@ -463,6 +464,9 @@ def optional_auth(**kwargs):
return "Authenticated"


def auth_exception():
return 'foo'

def test_args_kwargs(*args, **kwargs):
return kwargs

Expand Down Expand Up @@ -569,6 +573,10 @@ def jwt_info(token):
return None


def apikey_exception(token):
raise OAuthProblem()


def get_add_operation_on_http_methods_only():
return ""

Expand Down
15 changes: 15 additions & 0 deletions tests/fixtures/aiohttp/openapi_secure.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,15 @@ paths:
responses:
'200':
$ref: "#/components/responses/Success"
'/fail_auth':
get:
summary: Authentication will always fail
operationId: fakeapi.aiohttp_handlers.aiohttp_async_auth_exception
responses:
'200':
$ref: "#/components/responses/Success"
security:
- api_key_fail: []
components:
responses:
Success:
Expand Down Expand Up @@ -97,3 +106,9 @@ components:
type: http
scheme: bearer
x-bearerInfoFunc: fakeapi.auth.async_json_auth

api_key_fail:
type: apiKey
in: header
name: X-API-Key-2
x-apikeyInfoFunc: fakeapi.auth.async_auth_exception
14 changes: 14 additions & 0 deletions tests/fixtures/aiohttp/swagger_secure.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@ securityDefinitions:
in: header
name: X-API-Key
x-apikeyInfoFunc: fakeapi.auth.fake_json_auth
api_key_fail:
type: apiKey
in: header
name: X-API-Key-2
x-apikeyInfoFunc: fakeapi.auth.async_auth_exception

security:
- oauth:
Expand All @@ -38,3 +43,12 @@ paths:
description: greeting response
schema:
type: object
/fail_auth:
get:
summary: Authentication will always fail
operationId: fakeapi.aiohttp_handlers.aiohttp_async_auth_exception
responses:
200:
description: response
security:
- api_key_fail: []
16 changes: 16 additions & 0 deletions tests/fixtures/secure_endpoint/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,17 @@ paths:
responses:
'200':
description: some response
/auth-exception:
get:
summary: Test security handler function that raises an exception
description: Throw error from security function
operationId: fakeapi.hello.auth_exception
security:
- auth_exception: []
responses:
'200':
description: some response

servers:
- url: /v1.0
components:
Expand All @@ -161,3 +172,8 @@ components:
scheme: bearer
bearerFormat: JWT
x-bearerInfoFunc: fakeapi.hello.jwt_info
auth_exception:
type: apiKey
name: X-Api-Key
in: header
x-apikeyInfoFunc: fakeapi.hello.apikey_exception
17 changes: 17 additions & 0 deletions tests/fixtures/secure_endpoint/swagger.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,12 @@ securityDefinitions:
x-authentication-scheme: Bearer
x-bearerInfoFunc: fakeapi.hello.jwt_info

auth_exception:
type: apiKey
name: X-Api-Key
in: header
x-apikeyInfoFunc: fakeapi.hello.apikey_exception

paths:
/byesecure/{name}:
get:
Expand Down Expand Up @@ -171,3 +177,14 @@ paths:
responses:
'200':
description: some response

/auth-exception:
get:
summary: Test security handler function that raises an exception
description: Throw error from security function
operationId: fakeapi.hello.auth_exception
security:
- auth_exception: []
responses:
'200':
description: some response

0 comments on commit c71b116

Please sign in to comment.