Files
connexion/tests/api/test_secure_api.py
João Santos 44ea9336fe Connexion 2.0 (#619)
- App and Api options must be provided through the "options" argument (``old_style_options`` have been removed).
- You must specify a form content-type in 'consumes' in order to consume form data.
- The `Operation` interface has been formalized in the `AbstractOperation` class.
- The `Operation` class has been renamed to `Swagger2Operation`.
- Array parameter deserialization now follows the Swagger 2.0 spec more closely.
  In situations when a query parameter is passed multiple times, and the collectionFormat is either csv or pipes, the right-most value will be used.
  For example, `?q=1,2,3&q=4,5,6` will result in `q = [4, 5, 6]`.
  The old behavior is available by setting the collectionFormat to `multi`, or by importing `decorators.uri_parsing.AlwaysMultiURIParser` and passing `parser_class=AlwaysMultiURIParser` to your Api.
- The spec validator library has changed from `swagger-spec-validator` to `openapi-spec-validator`.
- Errors that previously raised `SwaggerValidationError` now raise the `InvalidSpecification` exception.
  All spec validation errors should be wrapped with `InvalidSpecification`.
- Support for nullable/x-nullable, readOnly and writeOnly/x-writeOnly has been added to the standard json schema validator.
- Custom validators can now be specified on api level (instead of app level).
- Added support for basic authentication and apikey authentication
- If unsupported security requirements are defined or ``x-tokenInfoFunc``/``x-tokenInfoUrl`` is missing, connexion now denies requests instead of allowing access without security-check.
- Accessing ``connexion.request.user`` / ``flask.request.user`` is no longer supported, use ``connexion.context['user']`` instead
2018-11-05 14:50:42 +01:00

116 lines
5.8 KiB
Python

import json
from connexion import FlaskApp
def test_security_over_nonexistent_endpoints(oauth_requests, secure_api_app):
app_client = secure_api_app.app.test_client()
headers = {"Authorization": "Bearer 300"}
get_inexistent_endpoint = app_client.get('/v1.0/does-not-exist-invalid-token',
headers=headers) # type: flask.Response
assert get_inexistent_endpoint.status_code == 401
assert get_inexistent_endpoint.content_type == 'application/problem+json'
headers = {"Authorization": "Bearer 100"}
get_inexistent_endpoint = app_client.get('/v1.0/does-not-exist-valid-token',
headers=headers) # type: flask.Response
assert get_inexistent_endpoint.status_code == 404
assert get_inexistent_endpoint.content_type == 'application/problem+json'
get_inexistent_endpoint = app_client.get('/v1.0/does-not-exist-no-token') # type: flask.Response
assert get_inexistent_endpoint.status_code == 401
swagger_ui = app_client.get('/v1.0/ui/') # type: flask.Response
assert swagger_ui.status_code == 401
headers = {"Authorization": "Bearer 100"}
post_greeting = app_client.post('/v1.0/greeting/rcaricio', data={}, headers=headers) # type: flask.Response
assert post_greeting.status_code == 200
post_greeting = app_client.post('/v1.0/greeting/rcaricio', data={}) # type: flask.Response
assert post_greeting.status_code == 401
def test_security(oauth_requests, secure_endpoint_app):
app_client = secure_endpoint_app.app.test_client()
get_bye_no_auth = app_client.get('/v1.0/byesecure/jsantos') # type: flask.Response
assert get_bye_no_auth.status_code == 401
assert get_bye_no_auth.content_type == 'application/problem+json'
get_bye_no_auth_reponse = json.loads(get_bye_no_auth.data.decode('utf-8', 'replace')) # type: dict
assert get_bye_no_auth_reponse['title'] == 'Unauthorized'
assert get_bye_no_auth_reponse['detail'] == "No authorization token provided"
headers = {"Authorization": "Bearer 100"}
get_bye_good_auth = app_client.get('/v1.0/byesecure/jsantos', headers=headers) # type: flask.Response
assert get_bye_good_auth.status_code == 200
assert get_bye_good_auth.data == b'Goodbye jsantos (Secure: test-user)'
headers = {"Authorization": "Bearer 200"}
get_bye_wrong_scope = app_client.get('/v1.0/byesecure/jsantos', headers=headers) # type: flask.Response
assert get_bye_wrong_scope.status_code == 403
assert get_bye_wrong_scope.content_type == 'application/problem+json'
get_bye_wrong_scope_reponse = json.loads(get_bye_wrong_scope.data.decode('utf-8', 'replace')) # type: dict
assert get_bye_wrong_scope_reponse['title'] == 'Forbidden'
assert get_bye_wrong_scope_reponse['detail'] == "Provided token doesn't have the required scope"
headers = {"Authorization": "Bearer 300"}
get_bye_bad_token = app_client.get('/v1.0/byesecure/jsantos', headers=headers) # type: flask.Response
assert get_bye_bad_token.status_code == 401
assert get_bye_bad_token.content_type == 'application/problem+json'
get_bye_bad_token_reponse = json.loads(get_bye_bad_token.data.decode('utf-8', 'replace')) # type: dict
assert get_bye_bad_token_reponse['title'] == 'Unauthorized'
assert get_bye_bad_token_reponse['detail'] == "Provided oauth token is not valid"
response = app_client.get('/v1.0/more-than-one-security-definition') # type: flask.Response
assert response.status_code == 401
# also tests case-insensitivity
headers = {"X-AUTH": "mykey"}
response = app_client.get('/v1.0/more-than-one-security-definition', headers=headers) # type: flask.Response
assert response.status_code == 200
headers = {"Authorization": "Bearer 100"}
get_bye_good_auth = app_client.get('/v1.0/byesecure-ignoring-context/hjacobs',
headers=headers) # type: flask.Response
assert get_bye_good_auth.status_code == 200
assert get_bye_good_auth.data == b'Goodbye hjacobs (Secure!)'
headers = {"Authorization": "Bearer 100"}
get_bye_from_flask = app_client.get('/v1.0/byesecure-from-flask', headers=headers) # type: flask.Response
assert get_bye_from_flask.data == b'Goodbye test-user (Secure!)'
headers = {"Authorization": "Bearer 100"}
get_bye_from_connexion = app_client.get('/v1.0/byesecure-from-connexion', headers=headers) # type: flask.Response
assert get_bye_from_connexion.data == b'Goodbye test-user (Secure!)'
def test_checking_that_client_token_has_all_necessary_scopes(
oauth_requests, secure_endpoint_app):
app_client = secure_endpoint_app.app.test_client()
# has only one of the required scopes
headers = {"Authorization": "Bearer has_myscope"}
response = app_client.get('/v1.0/more-than-one-scope', headers=headers) # type: flask.Response
assert response.status_code == 403
# has none of the necessary scopes
headers = {"Authorization": "Bearer has_wrongscope"}
response = app_client.get('/v1.0/more-than-one-scope', headers=headers) # type: flask.Response
assert response.status_code == 403
# is not auth
headers = {"Authorization": "Bearer is_not_invalid"}
response = app_client.get('/v1.0/more-than-one-scope', headers=headers) # type: flask.Response
assert response.status_code == 401
# has all necessary scopes
headers = {"Authorization": "Bearer has_myscope_otherscope"}
response = app_client.get('/v1.0/more-than-one-scope', headers=headers) # type: flask.Response
assert response.status_code == 200
# has all necessary scopes but under key 'scopes'
headers = {"Authorization": "Bearer has_scopes_in_scopes_with_s"}
response = app_client.get('/v1.0/more-than-one-scope', headers=headers) # type: flask.Response
assert response.status_code == 200