diff --git a/app/schemas.py b/app/schemas.py index 3a0ab41df..050e35d48 100644 --- a/app/schemas.py +++ b/app/schemas.py @@ -1,4 +1,5 @@ import re +from flask import current_app from flask_marshmallow.fields import fields from . import ma from . import models @@ -102,12 +103,15 @@ class SmsTemplateNotificationSchema(SmsNotificationSchema): @validates_schema def validate_schema(self, data): """ - Validate the to field is valid for this template + Validate the to field is valid for this notification """ + from app import api_user template_id = data.get('template', None) template = models.Template.query.filter_by(id=template_id).first() if template: service = template.service + # Validate restricted service, + # restricted services can only send to one of its users. if service.restricted: valid = False for usr in service.users: @@ -116,6 +120,11 @@ class SmsTemplateNotificationSchema(SmsNotificationSchema): break if not valid: raise ValidationError('Invalid phone number for restricted service', 'restricted') + # Assert the template is valid for the service which made the request. + service = api_user['client'] + if (service != current_app.config.get('ADMIN_CLIENT_USER_NAME') and + template.service != models.Service.query.filter_by(id=service).first()): + raise ValidationError('Invalid template', 'restricted') class SmsAdminNotificationSchema(SmsNotificationSchema): diff --git a/tests/app/notifications/test_rest.py b/tests/app/notifications/test_rest.py index d3c2170e8..33cef53b0 100644 --- a/tests/app/notifications/test_rest.py +++ b/tests/app/notifications/test_rest.py @@ -4,6 +4,8 @@ import uuid from tests import create_authorization_header from flask import url_for, json from app.models import Service +from tests.app.conftest import sample_service as create_sample_service +from tests.app.conftest import sample_template as create_sample_template def test_get_notifications( @@ -172,6 +174,38 @@ def test_send_notification_invalid_template_id(notify_api, assert 'Template not found' in json_resp['message']['template'] +@moto.mock_sqs +def test_should_not_allow_template_from_other_service(notify_api, + notify_db, + notify_db_session, + sample_template, + sample_admin_service_id, + mocker): + """ + Tests POST endpoint '/sms' with notifications. + """ + with notify_api.test_request_context(): + with notify_api.test_client() as client: + data = { + 'to': '+441234123123', + 'template': sample_template.id + } + auth_header = create_authorization_header( + service_id=sample_admin_service_id, + request_body=json.dumps(data), + path=url_for('notifications.create_sms_notification'), + method='POST') + + response = client.post( + url_for('notifications.create_sms_notification'), + data=json.dumps(data), + headers=[('Content-Type', 'application/json'), auth_header]) + + json_resp = json.loads(response.get_data(as_text=True)) + assert response.status_code == 400 + assert 'Invalid template' in json_resp['message']['restricted'] + + @moto.mock_sqs def test_should_allow_valid_message(notify_api, notify_db,