Rewrite requires_admin_auth tests to be generic

This adds previously missing tests and changes the existing ones
to test the "requires_internal_auth" function directly. In order
to make the tests generic, we have a fake auth function and an
associated fixture.

Having generic tests for internal auth will make it easier to add
other "requires..." functions in future.
This commit is contained in:
Ben Thorner
2021-07-29 11:52:25 +01:00
parent 193e7e0004
commit f5d2edaa0a

View File

@@ -3,7 +3,7 @@ import uuid
import jwt import jwt
import pytest import pytest
from flask import current_app, request from flask import current_app, g, request
from notifications_python_client.authentication import create_jwt_token from notifications_python_client.authentication import create_jwt_token
from app import api_user from app import api_user
@@ -14,6 +14,7 @@ from app.authentication.auth import (
_get_auth_token, _get_auth_token,
_get_token_issuer, _get_token_issuer,
requires_auth, requires_auth,
requires_internal_auth,
) )
from app.dao.api_key_dao import ( from app.dao.api_key_dao import (
expire_api_key, expire_api_key,
@@ -24,6 +25,23 @@ from app.dao.services_dao import dao_fetch_service_by_id
from tests.conftest import set_config_values from tests.conftest import set_config_values
@pytest.fixture
def internal_jwt_token(notify_api):
with set_config_values(notify_api, {
'INTERNAL_CLIENT_API_KEYS': {
'my-internal-app': ['my-internal-app-secret'],
}
}):
yield create_jwt_token(
client_id='my-internal-app',
secret='my-internal-app-secret'
)
def requires_my_internal_app_auth():
requires_internal_auth('my-internal-app')
def create_custom_jwt_token(headers=None, payload=None, key=None): def create_custom_jwt_token(headers=None, payload=None, key=None):
# code copied from notifications_python_client.authentication.py::create_jwt_token # code copied from notifications_python_client.authentication.py::create_jwt_token
headers = headers or {"typ": 'JWT', "alg": 'HS256'} headers = headers or {"typ": 'JWT', "alg": 'HS256'}
@@ -43,13 +61,6 @@ def service_jwt_token(sample_api_key, service_jwt_secret):
) )
@pytest.fixture
def admin_jwt_token():
admin_jwt_client_id = current_app.config['ADMIN_CLIENT_USER_NAME']
admin_jwt_secret = current_app.config['INTERNAL_CLIENT_API_KEYS'][admin_jwt_client_id][0]
return create_jwt_token(admin_jwt_secret, admin_jwt_client_id)
def test_requires_auth_should_allow_valid_token_for_request_with_path_params_for_public_url( def test_requires_auth_should_allow_valid_token_for_request_with_path_params_for_public_url(
client, client,
service_jwt_token, service_jwt_token,
@@ -58,10 +69,11 @@ def test_requires_auth_should_allow_valid_token_for_request_with_path_params_for
assert response.status_code == 200 assert response.status_code == 200
def test_requires_admin_auth_should_allow_valid_token_for_request_with_path_params( def test_requires_admin_auth_should_allow_valid_token_for_request_with_path_params(client):
client, admin_jwt_client_id = current_app.config['ADMIN_CLIENT_USER_NAME']
admin_jwt_token admin_jwt_secret = current_app.config['INTERNAL_CLIENT_API_KEYS'][admin_jwt_client_id][0]
): admin_jwt_token = create_jwt_token(admin_jwt_secret, admin_jwt_client_id)
response = client.get('/service', headers={'Authorization': 'Bearer {}'.format(admin_jwt_token)}) response = client.get('/service', headers={'Authorization': 'Bearer {}'.format(admin_jwt_token)})
assert response.status_code == 200 assert response.status_code == 200
@@ -286,34 +298,44 @@ def test_requires_auth_should_attach_the_current_api_key_to_current_app(
assert str(api_user.id) == str(sample_api_key.id) assert str(api_user.id) == str(sample_api_key.id)
@pytest.mark.parametrize('check_proxy_header,header_value,expected_status', [ def test_requires_internal_auth_checks_proxy_key(
(True, 'key_1', 200), client,
(True, 'wrong_key', 403), mocker,
(False, 'key_1', 200), internal_jwt_token,
(False, 'wrong_key', 200),
])
def test_requires_admin_auth_proxy_key(
notify_api,
check_proxy_header,
header_value,
expected_status,
admin_jwt_token,
): ):
with set_config_values(notify_api, { proxy_check_mock = mocker.patch(
'ROUTE_SECRET_KEY_1': 'key_1', 'app.authentication.auth.request_helper.check_proxy_header_before_request'
'ROUTE_SECRET_KEY_2': '', )
'CHECK_PROXY_HEADER': check_proxy_header,
}):
with notify_api.test_client() as client: request.headers = {'Authorization': 'Bearer {}'.format(internal_jwt_token)}
response = client.get( requires_my_internal_app_auth()
path='/service', proxy_check_mock.assert_called_once()
headers=[
('X-Custom-Forwarder', header_value),
('Authorization', 'Bearer {}'.format(admin_jwt_token)) def test_requires_internal_auth_errors_for_unknown_app(client):
] with pytest.raises(TypeError) as exc:
) requires_internal_auth('another-app')
assert response.status_code == expected_status assert str(exc.value) == 'Unknown client_id for internal auth'
def test_requires_internal_auth_errors_for_api_app_mismatch(
client,
internal_jwt_token,
service_jwt_token
):
request.headers = {'Authorization': 'Bearer {}'.format(service_jwt_token)}
with pytest.raises(AuthError) as exc:
requires_my_internal_app_auth()
assert exc.value.short_message == 'Unauthorized: not allowed to perform this action'
def test_requires_internal_auth_sets_global_variables(
client,
internal_jwt_token,
):
request.headers = {'Authorization': 'Bearer {}'.format(internal_jwt_token)}
requires_my_internal_app_auth()
assert g.service_id == 'my-internal-app'
def test_requires_auth_should_cache_service_and_api_key_lookups( def test_requires_auth_should_cache_service_and_api_key_lookups(