mirror of
https://github.com/GSA/notifications-api.git
synced 2026-09-08 08:28:24 -04:00
Merge pull request #1492 from alphagov/add-mmg-inbound-sms-auth
Add MMG_INBOUND_SMS_AUTH config variable and auth check
This commit is contained in:
@@ -48,6 +48,8 @@ def extract_notify_config(notify_config):
|
|||||||
os.environ['DANGEROUS_SALT'] = notify_config['credentials']['dangerous_salt']
|
os.environ['DANGEROUS_SALT'] = notify_config['credentials']['dangerous_salt']
|
||||||
os.environ['SMS_INBOUND_WHITELIST'] = json.dumps(notify_config['credentials']['allow_ip_inbound_sms'])
|
os.environ['SMS_INBOUND_WHITELIST'] = json.dumps(notify_config['credentials']['allow_ip_inbound_sms'])
|
||||||
os.environ['FIRETEXT_INBOUND_SMS_AUTH'] = json.dumps(notify_config['credentials']['firetext_inbound_sms_auth'])
|
os.environ['FIRETEXT_INBOUND_SMS_AUTH'] = json.dumps(notify_config['credentials']['firetext_inbound_sms_auth'])
|
||||||
|
os.environ['MMG_INBOUND_SMS_AUTH'] = json.dumps(notify_config['credentials']['mmg_inbound_sms_auth'])
|
||||||
|
os.environ['MMG_INBOUND_SMS_USERNAME'] = json.dumps(notify_config['credentials']['mmg_inbound_sms_username'])
|
||||||
os.environ['ROUTE_SECRET_KEY_1'] = notify_config['credentials']['route_secret_key_1']
|
os.environ['ROUTE_SECRET_KEY_1'] = notify_config['credentials']['route_secret_key_1']
|
||||||
os.environ['ROUTE_SECRET_KEY_2'] = notify_config['credentials']['route_secret_key_2']
|
os.environ['ROUTE_SECRET_KEY_2'] = notify_config['credentials']['route_secret_key_2']
|
||||||
|
|
||||||
|
|||||||
@@ -300,6 +300,8 @@ class Config(object):
|
|||||||
|
|
||||||
SMS_INBOUND_WHITELIST = json.loads(os.environ.get('SMS_INBOUND_WHITELIST', '[]'))
|
SMS_INBOUND_WHITELIST = json.loads(os.environ.get('SMS_INBOUND_WHITELIST', '[]'))
|
||||||
FIRETEXT_INBOUND_SMS_AUTH = json.loads(os.environ.get('FIRETEXT_INBOUND_SMS_AUTH', '[]'))
|
FIRETEXT_INBOUND_SMS_AUTH = json.loads(os.environ.get('FIRETEXT_INBOUND_SMS_AUTH', '[]'))
|
||||||
|
MMG_INBOUND_SMS_AUTH = json.loads(os.environ.get('MMG_INBOUND_SMS_AUTH', '[]'))
|
||||||
|
MMG_INBOUND_SMS_USERNAME = json.loads(os.environ.get('MMG_INBOUND_SMS_USERNAME', '[]'))
|
||||||
|
|
||||||
ROUTE_SECRET_KEY_1 = os.environ.get('ROUTE_SECRET_KEY_1', '')
|
ROUTE_SECRET_KEY_1 = os.environ.get('ROUTE_SECRET_KEY_1', '')
|
||||||
ROUTE_SECRET_KEY_2 = os.environ.get('ROUTE_SECRET_KEY_2', '')
|
ROUTE_SECRET_KEY_2 = os.environ.get('ROUTE_SECRET_KEY_2', '')
|
||||||
@@ -376,6 +378,8 @@ class Test(Config):
|
|||||||
|
|
||||||
SMS_INBOUND_WHITELIST = ['203.0.113.195']
|
SMS_INBOUND_WHITELIST = ['203.0.113.195']
|
||||||
FIRETEXT_INBOUND_SMS_AUTH = ['testkey']
|
FIRETEXT_INBOUND_SMS_AUTH = ['testkey']
|
||||||
|
MMG_INBOUND_SMS_AUTH = ['testkey']
|
||||||
|
MMG_INBOUND_SMS_USERNAME = ['username']
|
||||||
TEMPLATE_PREVIEW_API_HOST = 'http://localhost:9999'
|
TEMPLATE_PREVIEW_API_HOST = 'http://localhost:9999'
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -30,6 +30,16 @@ def receive_mmg_sms():
|
|||||||
"""
|
"""
|
||||||
post_data = request.get_json()
|
post_data = request.get_json()
|
||||||
|
|
||||||
|
auth = request.authorization
|
||||||
|
|
||||||
|
if not auth:
|
||||||
|
current_app.logger.warning("Inbound sms (MMG) no auth header")
|
||||||
|
# abort(401)
|
||||||
|
elif auth.username not in current_app.config['MMG_INBOUND_SMS_USERNAME'] \
|
||||||
|
or auth.password not in current_app.config['MMG_INBOUND_SMS_AUTH']:
|
||||||
|
current_app.logger.warning("Inbound sms (MMG) incorrect username ({}) or password".format(auth.username))
|
||||||
|
# abort(403)
|
||||||
|
|
||||||
inbound_number = strip_leading_forty_four(post_data['Number'])
|
inbound_number = strip_leading_forty_four(post_data['Number'])
|
||||||
|
|
||||||
service = fetch_potential_service(inbound_number, 'mmg')
|
service = fetch_potential_service(inbound_number, 'mmg')
|
||||||
@@ -49,20 +59,23 @@ def receive_mmg_sms():
|
|||||||
|
|
||||||
tasks.send_inbound_sms_to_service.apply_async([str(inbound.id), str(service.id)], queue=QueueNames.NOTIFY)
|
tasks.send_inbound_sms_to_service.apply_async([str(inbound.id), str(service.id)], queue=QueueNames.NOTIFY)
|
||||||
|
|
||||||
return 'RECEIVED', 200
|
current_app.logger.info(
|
||||||
|
'{} received inbound SMS with reference {} from MMG'.format(service.id, inbound.provider_reference))
|
||||||
|
return jsonify({
|
||||||
|
"status": "ok"
|
||||||
|
}), 200
|
||||||
|
|
||||||
|
|
||||||
@receive_notifications_blueprint.route('/notifications/sms/receive/firetext', methods=['POST'])
|
@receive_notifications_blueprint.route('/notifications/sms/receive/firetext', methods=['POST'])
|
||||||
def receive_firetext_sms():
|
def receive_firetext_sms():
|
||||||
post_data = request.form
|
post_data = request.form
|
||||||
|
|
||||||
# This is pre-implementation test code to validate the provider is basic auth headers.
|
|
||||||
auth = request.authorization
|
auth = request.authorization
|
||||||
if not auth:
|
if not auth:
|
||||||
current_app.logger.warning("Inbound sms no auth header")
|
current_app.logger.warning("Inbound sms (Firetext) no auth header")
|
||||||
abort(401)
|
abort(401)
|
||||||
elif auth.username != 'notify' or auth.password not in current_app.config['FIRETEXT_INBOUND_SMS_AUTH']:
|
elif auth.username != 'notify' or auth.password not in current_app.config['FIRETEXT_INBOUND_SMS_AUTH']:
|
||||||
current_app.logger.warning("Inbound sms incorrect username ({}) or password".format(auth.username))
|
current_app.logger.warning("Inbound sms (Firetext) incorrect username ({}) or password".format(auth.username))
|
||||||
abort(403)
|
abort(403)
|
||||||
|
|
||||||
inbound_number = strip_leading_forty_four(post_data['destination'])
|
inbound_number = strip_leading_forty_four(post_data['destination'])
|
||||||
|
|||||||
@@ -37,14 +37,21 @@ def firetext_post(client, data, auth=True, password='testkey'):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def mmg_post(client, data):
|
def mmg_post(client, data, auth=True, password='testkey'):
|
||||||
|
headers = [
|
||||||
|
('Content-Type', 'application/json'),
|
||||||
|
('X-Forwarded-For', '203.0.113.195, 70.41.3.18, 150.172.238.178')
|
||||||
|
]
|
||||||
|
|
||||||
|
if auth:
|
||||||
|
auth_value = base64.b64encode("username:{}".format(password).encode('utf-8')).decode('utf-8')
|
||||||
|
headers.append(('Authorization', 'Basic ' + auth_value))
|
||||||
|
|
||||||
return client.post(
|
return client.post(
|
||||||
path='/notifications/sms/receive/mmg',
|
path='/notifications/sms/receive/mmg',
|
||||||
data=json.dumps(data),
|
data=json.dumps(data),
|
||||||
headers=[
|
headers=headers
|
||||||
('Content-Type', 'application/json'),
|
)
|
||||||
('X-Forwarded-For', '203.0.113.195, 70.41.3.18, 150.172.238.178')
|
|
||||||
])
|
|
||||||
|
|
||||||
|
|
||||||
def test_receive_notification_returns_received_to_mmg(client, mocker, sample_service_full_permissions):
|
def test_receive_notification_returns_received_to_mmg(client, mocker, sample_service_full_permissions):
|
||||||
@@ -61,7 +68,9 @@ def test_receive_notification_returns_received_to_mmg(client, mocker, sample_ser
|
|||||||
response = mmg_post(client, data)
|
response = mmg_post(client, data)
|
||||||
|
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
assert response.get_data(as_text=True) == 'RECEIVED'
|
result = json.loads(response.get_data(as_text=True))
|
||||||
|
assert result['status'] == 'ok'
|
||||||
|
|
||||||
inbound_sms_id = InboundSms.query.all()[0].id
|
inbound_sms_id = InboundSms.query.all()[0].id
|
||||||
mocked.assert_called_once_with(
|
mocked.assert_called_once_with(
|
||||||
[str(inbound_sms_id), str(sample_service_full_permissions.id)], queue="notify-internal-tasks")
|
[str(inbound_sms_id), str(sample_service_full_permissions.id)], queue="notify-internal-tasks")
|
||||||
@@ -411,6 +420,39 @@ def test_firetext_inbound_sms_auth(notify_db_session, notify_api, client, mocker
|
|||||||
assert response.status_code == status_code
|
assert response.status_code == status_code
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("auth, keys, status_code", [
|
||||||
|
["testkey", ["testkey"], 200],
|
||||||
|
["", ["testkey"], 401],
|
||||||
|
["wrong", ["testkey"], 403],
|
||||||
|
["testkey1", ["testkey1", "testkey2"], 200],
|
||||||
|
["testkey2", ["testkey1", "testkey2"], 200],
|
||||||
|
["wrong", ["testkey1", "testkey2"], 403],
|
||||||
|
["", [], 401],
|
||||||
|
["testkey", [], 403],
|
||||||
|
])
|
||||||
|
@pytest.mark.skip(reason="aborts are disabled at the moment")
|
||||||
|
def test_mmg_inbound_sms_auth(notify_db_session, notify_api, client, mocker, auth, keys, status_code):
|
||||||
|
mocker.patch("app.notifications.receive_notifications.tasks.send_inbound_sms_to_service.apply_async")
|
||||||
|
|
||||||
|
create_service_with_inbound_number(
|
||||||
|
service_name='b', inbound_number='07111111111', service_permissions=[EMAIL_TYPE, SMS_TYPE, INBOUND_SMS_TYPE]
|
||||||
|
)
|
||||||
|
|
||||||
|
data = {
|
||||||
|
"ID": "1234",
|
||||||
|
"MSISDN": "07111111111",
|
||||||
|
"Message": "Some message to notify",
|
||||||
|
"Trigger": "Trigger?",
|
||||||
|
"Number": "testing",
|
||||||
|
"Channel": "SMS",
|
||||||
|
"DateRecieved": "2012-06-27 12:33:00"
|
||||||
|
}
|
||||||
|
|
||||||
|
with set_config(notify_api, 'MMG_INBOUND_SMS_AUTH', keys):
|
||||||
|
response = mmg_post(client, data, auth=bool(auth), password=auth)
|
||||||
|
assert response.status_code == status_code
|
||||||
|
|
||||||
|
|
||||||
def test_create_inbound_sms_object_works_with_alphanumeric_sender(sample_service_full_permissions):
|
def test_create_inbound_sms_object_works_with_alphanumeric_sender(sample_service_full_permissions):
|
||||||
data = {
|
data = {
|
||||||
'Message': 'hello',
|
'Message': 'hello',
|
||||||
|
|||||||
@@ -18,6 +18,8 @@ def notify_config():
|
|||||||
'dangerous_salt': 'dangerous salt',
|
'dangerous_salt': 'dangerous salt',
|
||||||
'allow_ip_inbound_sms': ['111.111.111.111', '100.100.100.100'],
|
'allow_ip_inbound_sms': ['111.111.111.111', '100.100.100.100'],
|
||||||
'firetext_inbound_sms_auth': ['testkey'],
|
'firetext_inbound_sms_auth': ['testkey'],
|
||||||
|
'mmg_inbound_sms_auth': ['testkey'],
|
||||||
|
'mmg_inbound_sms_username': ['username'],
|
||||||
'route_secret_key_1': "key_1",
|
'route_secret_key_1': "key_1",
|
||||||
'route_secret_key_2': ""
|
'route_secret_key_2': ""
|
||||||
}
|
}
|
||||||
@@ -232,6 +234,20 @@ def test_firetext_inbound_sms_auth_config():
|
|||||||
assert os.environ['FIRETEXT_INBOUND_SMS_AUTH'] == json.dumps(['testkey'])
|
assert os.environ['FIRETEXT_INBOUND_SMS_AUTH'] == json.dumps(['testkey'])
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.usefixtures('os_environ', 'cloudfoundry_environ')
|
||||||
|
def test_mmg_inbound_sms_auth_config():
|
||||||
|
extract_cloudfoundry_config()
|
||||||
|
|
||||||
|
assert os.environ['MMG_INBOUND_SMS_AUTH'] == json.dumps(['testkey'])
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.usefixtures('os_environ', 'cloudfoundry_environ')
|
||||||
|
def test_mmg_inbound_sms_username_config():
|
||||||
|
extract_cloudfoundry_config()
|
||||||
|
|
||||||
|
assert os.environ['MMG_INBOUND_SMS_USERNAME'] == json.dumps(['username'])
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.usefixtures('os_environ', 'cloudfoundry_environ')
|
@pytest.mark.usefixtures('os_environ', 'cloudfoundry_environ')
|
||||||
def test_performance_platform_config():
|
def test_performance_platform_config():
|
||||||
extract_cloudfoundry_config()
|
extract_cloudfoundry_config()
|
||||||
|
|||||||
Reference in New Issue
Block a user