Merge branch 'master' of github.com:alphagov/notifications-api

This commit is contained in:
Rebecca Law
2016-04-15 14:51:35 +01:00
4 changed files with 31 additions and 30 deletions

View File

@@ -1,6 +1,6 @@
from flask import request, jsonify, _request_ctx_stack, current_app from flask import request, jsonify, _request_ctx_stack, current_app
from notifications_python_client.authentication import decode_jwt_token, get_token_issuer from notifications_python_client.authentication import decode_jwt_token, get_token_issuer
from notifications_python_client.errors import TokenDecodeError, TokenRequestError, TokenExpiredError, TokenPayloadError from notifications_python_client.errors import TokenDecodeError, TokenExpiredError
from werkzeug.exceptions import abort from werkzeug.exceptions import abort
from app.dao.api_key_dao import get_unsigned_secrets from app.dao.api_key_dao import get_unsigned_secrets
from app import api_user from app import api_user
@@ -43,12 +43,8 @@ def requires_auth():
) )
_request_ctx_stack.top.api_user = api_client _request_ctx_stack.top.api_user = api_client
return return
except TokenRequestError:
errors_resp = authentication_response("Invalid token: request", 403)
except TokenExpiredError: except TokenExpiredError:
errors_resp = authentication_response("Invalid token: expired", 403) errors_resp = authentication_response("Invalid token: expired", 403)
except TokenPayloadError:
errors_resp = authentication_response("Invalid token: payload", 403)
except TokenDecodeError: except TokenDecodeError:
errors_resp = authentication_response("Invalid token: signature", 403) errors_resp = authentication_response("Invalid token: signature", 403)

View File

@@ -10,7 +10,7 @@ from app.clients.sms.mmg import MMGClientException
from app.dao.services_dao import dao_fetch_service_by_id from app.dao.services_dao import dao_fetch_service_by_id
from app.dao.templates_dao import dao_get_template_by_id from app.dao.templates_dao import dao_get_template_by_id
from notifications_utils.template import Template from notifications_utils.template import Template, unlink_govuk_escaped
from notifications_utils.recipients import ( from notifications_utils.recipients import (
RecipientCSV, RecipientCSV,
@@ -296,7 +296,7 @@ def send_email(service_id, notification_id, from_address, encrypted_notification
from_address, from_address,
notification['to'], notification['to'],
template.replaced_subject, template.replaced_subject,
body=template.replaced, body=template.replaced_govuk_escaped,
html_body=template.as_HTML_email, html_body=template.as_HTML_email,
) )
update_notification_reference_by_id(notification_id, reference) update_notification_reference_by_id(notification_id, reference)
@@ -350,13 +350,17 @@ def invitation_template(user_name, service_name, url, expiry_date):
'GOV.UK Notify makes it easy to keep people updated by helping you send text messages, emails and letters.\n\n' 'GOV.UK Notify makes it easy to keep people updated by helping you send text messages, emails and letters.\n\n'
'Click this link to create an account on GOV.UK Notify:\n$url\n\n' 'Click this link to create an account on GOV.UK Notify:\n$url\n\n'
'This invitation will stop working at midnight tomorrow. This is to keep $service_name secure.') 'This invitation will stop working at midnight tomorrow. This is to keep $service_name secure.')
return t.substitute(user_name=user_name, service_name=service_name, url=url, expiry_date=expiry_date) return unlink_govuk_escaped(
t.substitute(user_name=user_name, service_name=service_name, url=url, expiry_date=expiry_date)
)
def invitation_subject_line(user_name, service_name): def invitation_subject_line(user_name, service_name):
from string import Template from string import Template
t = Template('$user_name has invited you to collaborate on $service_name on GOV.UK Notify') t = Template('$user_name has invited you to collaborate on $service_name on GOV.UK Notify')
return t.substitute(user_name=user_name, service_name=service_name) return unlink_govuk_escaped(
t.substitute(user_name=user_name, service_name=service_name)
)
def invited_user_url(base_url, token): def invited_user_url(base_url, token):
@@ -391,7 +395,9 @@ def password_reset_message(name, url):
"If you didn't request this email, you can ignore it your password has not been changed.\n\n" "If you didn't request this email, you can ignore it your password has not been changed.\n\n"
"To reset your password, click this link:\n\n" "To reset your password, click this link:\n\n"
"$url") "$url")
return t.substitute(user_name=name, url=url) return unlink_govuk_escaped(
t.substitute(user_name=name, url=url)
)
@notify_celery.task(name='email-reset-password') @notify_celery.task(name='email-reset-password')
@@ -411,7 +417,9 @@ def registration_verification_template(name, url):
from string import Template from string import Template
t = Template("Hi $name,\n\n" t = Template("Hi $name,\n\n"
"To complete your registration for GOV.UK Notify please click the link below\n\n $url") "To complete your registration for GOV.UK Notify please click the link below\n\n $url")
return t.substitute(name=name, url=url) return unlink_govuk_escaped(
t.substitute(name=name, url=url)
)
@notify_celery.task(name='email-registration-verification') @notify_celery.task(name='email-registration-verification')

View File

@@ -19,6 +19,7 @@ twilio==4.6.0
monotonic==0.3 monotonic==0.3
git+https://github.com/alphagov/notifications-python-client.git@0.2.6#egg=notifications-python-client==0.2.6 git+https://github.com/alphagov/notifications-python-client.git@0.5.0#egg=notifications-python-client==0.5.0
git+https://github.com/alphagov/notifications-utils.git@4.1.1#egg=notifications-utils==4.1.1
git+https://github.com/alphagov/notifications-utils.git@4.2.0#egg=notifications-utils==4.2.0

View File

@@ -1,7 +1,8 @@
from datetime import datetime, timedelta from datetime import datetime, timedelta
import pytest
from notifications_python_client.authentication import create_jwt_token from notifications_python_client.authentication import create_jwt_token
from flask import json, url_for, current_app from flask import json, current_app
from app.dao.api_key_dao import get_unsigned_secrets, save_model_api_key, get_unsigned_secret from app.dao.api_key_dao import get_unsigned_secrets, save_model_api_key, get_unsigned_secret
from app.models import ApiKey, Service from app.models import ApiKey, Service
@@ -37,7 +38,7 @@ def test_should_not_allow_request_with_incorrect_token(notify_api, sample_user):
assert data['message'] == 'Invalid token: signature' assert data['message'] == 'Invalid token: signature'
def test_should_not_allow_incorrect_path(notify_api, sample_api_key): def test_should_ignore_path(notify_api, sample_api_key):
with notify_api.test_request_context(): with notify_api.test_request_context():
with notify_api.test_client() as client: with notify_api.test_client() as client:
token = create_jwt_token( token = create_jwt_token(
@@ -49,12 +50,10 @@ def test_should_not_allow_incorrect_path(notify_api, sample_api_key):
response = client.get( response = client.get(
'/service', '/service',
headers={'Authorization': "Bearer {}".format(token)}) headers={'Authorization': "Bearer {}".format(token)})
assert response.status_code == 403 assert response.status_code == 200
data = json.loads(response.get_data())
assert data['message'] == 'Invalid token: request'
def test_should_not_allow_incorrect_method(notify_api, sample_api_key): def test_should_ignore_request(notify_api, sample_api_key):
with notify_api.test_request_context(): with notify_api.test_request_context():
with notify_api.test_client() as client: with notify_api.test_client() as client:
token = __create_post_token(sample_api_key.service_id, {}) token = __create_post_token(sample_api_key.service_id, {})
@@ -62,9 +61,7 @@ def test_should_not_allow_incorrect_method(notify_api, sample_api_key):
'/service', '/service',
headers={'Authorization': "Bearer {}".format(token)} headers={'Authorization': "Bearer {}".format(token)}
) )
assert response.status_code == 403 assert response.status_code == 200
data = json.loads(response.get_data())
assert data['message'] == 'Invalid token: request'
def test_should_not_allow_invalid_secret(notify_api, sample_api_key): def test_should_not_allow_invalid_secret(notify_api, sample_api_key):
@@ -152,17 +149,16 @@ def test_should_allow_valid_token_with_post_body(notify_api, sample_api_key):
assert response.status_code == 200 assert response.status_code == 200
def test_should_not_allow_valid_token_with_invalid_post_body(notify_api, notify_db, notify_db_session, sample_api_key): def test_should_allow_valid_token_with_invalid_post_body_but_fail_at_endpoint(notify_api, sample_api_key):
with notify_api.test_request_context(): with notify_api.test_request_context():
with notify_api.test_client() as client: with notify_api.test_client() as client:
token = __create_post_token(str(sample_api_key.service_id), JSON_BODY) token = __create_post_token(str(sample_api_key.service_id), JSON_BODY)
response = client.post( with pytest.raises(AttributeError):
'/service', response = client.post(
data="spurious", '/service',
headers={'Authorization': 'Bearer {}'.format(token)}) data="spurious",
assert response.status_code == 403 headers={'Authorization': 'Bearer {}'.format(token)})
data = json.loads(response.get_data()) assert response.status_code == 400
assert data['message'] == 'Invalid token: payload'
def test_authentication_passes_admin_client_token(notify_api, def test_authentication_passes_admin_client_token(notify_api,