diff --git a/app/authentication/auth.py b/app/authentication/auth.py index 841222279..357151fba 100644 --- a/app/authentication/auth.py +++ b/app/authentication/auth.py @@ -3,7 +3,7 @@ from sqlalchemy.exc import DataError from sqlalchemy.orm.exc import NoResultFound from notifications_python_client.authentication import decode_jwt_token, get_token_issuer -from notifications_python_client.errors import TokenDecodeError, TokenExpiredError +from notifications_python_client.errors import TokenDecodeError, TokenExpiredError, TokenIssuerError from app.dao.api_key_dao import get_model_api_keys from app.dao.services_dao import dao_fetch_service_by_id @@ -39,8 +39,10 @@ def requires_auth(): auth_token = get_auth_token(request) try: client = get_token_issuer(auth_token) - except TokenDecodeError: - raise AuthError("Invalid token: signature", 403) + except TokenDecodeError as e: + raise AuthError(e.message, 403) + except TokenIssuerError: + raise AuthError("Invalid token: iss not provided", 403) if client == current_app.config.get('ADMIN_CLIENT_USER_NAME'): return handle_admin_key(auth_token, current_app.config.get('ADMIN_CLIENT_SECRET')) @@ -76,8 +78,8 @@ def handle_admin_key(auth_token, secret): try: get_decode_errors(auth_token, secret) return - except TokenDecodeError: - raise AuthError("Invalid token: signature", 403) + except TokenDecodeError as e: + raise AuthError(e.message, 403) def get_decode_errors(auth_token, unsigned_secret): diff --git a/requirements.txt b/requirements.txt index a71037824..594f12317 100644 --- a/requirements.txt +++ b/requirements.txt @@ -19,7 +19,7 @@ monotonic==1.2 statsd==3.2.1 jsonschema==2.5.1 -git+https://github.com/alphagov/notifications-python-client.git@1.3.0#egg=notifications-python-client==1.3.0 +git+https://github.com/alphagov/notifications-python-client.git@2.0.0#egg=notifications-python-client==2.0.0 git+https://github.com/alphagov/notifications-utils.git@9.1.1#egg=notifications-utils==9.1.1 diff --git a/tests/app/authentication/test_authentication.py b/tests/app/authentication/test_authentication.py index 3a6d5b4d2..be7217b07 100644 --- a/tests/app/authentication/test_authentication.py +++ b/tests/app/authentication/test_authentication.py @@ -1,3 +1,6 @@ +import jwt +import uuid +import time from datetime import datetime import pytest @@ -41,6 +44,46 @@ def test_should_not_allow_request_with_incorrect_token(notify_api, sample_user): assert data['message'] == {"token": ['Invalid token: signature']} +def test_should_not_allow_request_with_no_iss(client): + # code copied from notifications_python_client.authentication.py::create_jwt_token + headers = { + "typ": 'JWT', + "alg": 'HS256' + } + + claims = { + # 'iss': not provided + 'iat': int(time.time()) + } + + token = jwt.encode(payload=claims, key=str(uuid.uuid4()), headers=headers).decode() + + response = client.get('/service', headers={'Authorization': 'Bearer {}'.format(token)}) + assert response.status_code == 403 + data = json.loads(response.get_data()) + assert data['message'] == {"token": ['Invalid token: iss field not provided']} + + +def test_should_not_allow_request_with_no_iat(client, sample_api_key): + # code copied from notifications_python_client.authentication.py::create_jwt_token + headers = { + "typ": 'JWT', + "alg": 'HS256' + } + + claims = { + 'iss': str(sample_api_key.service_id) + # 'iat': not provided + } + + token = jwt.encode(payload=claims, key=str(uuid.uuid4()), headers=headers).decode() + + response = client.get('/service', headers={'Authorization': 'Bearer {}'.format(token)}) + assert response.status_code == 403 + data = json.loads(response.get_data()) + assert data['message'] == {"token": ['Invalid token: signature, api token is not valid']} + + def test_should_not_allow_invalid_secret(notify_api, sample_api_key): with notify_api.test_request_context(): with notify_api.test_client() as client: