Enforce order of permissions decorators

At the moment we mostly have `user_has_permissions` execute first. It
shouldn’t matter, but it feels right for us to check that a user is
logged in before we check their permissions to a service. Otherwise a
malicious user could (maybe) check if a service ID belongs to a real
service, and go on to do something malicious with that information.

This commit adds some extra test code to enforce that the order is
always the same.

N.B. decorators in Python execute from closest to furthest (from the
line on which the function is defined).
This commit is contained in:
Chris Hill-Scott
2019-07-01 13:45:21 +01:00
parent 91f2da8b68
commit 3da9e84ece
13 changed files with 179 additions and 159 deletions

View File

@@ -33,8 +33,8 @@ dummy_bearer_token = 'bearer_token_set'
@main.route("/services/<service_id>/api")
@login_required
@user_has_permissions('manage_api_keys')
@login_required
def api_integration(service_id):
callbacks_link = (
'.api_callbacks' if current_service.has_permission('inbound_sms')
@@ -48,15 +48,15 @@ def api_integration(service_id):
@main.route("/services/<service_id>/api/documentation")
@login_required
@user_has_permissions('manage_api_keys')
@login_required
def api_documentation(service_id):
return redirect(url_for('.documentation'), code=301)
@main.route("/services/<service_id>/api/whitelist", methods=['GET', 'POST'])
@login_required
@user_has_permissions('manage_api_keys')
@login_required
def whitelist(service_id):
form = Whitelist()
if form.validate_on_submit():
@@ -75,8 +75,8 @@ def whitelist(service_id):
@main.route("/services/<service_id>/api/keys")
@login_required
@user_has_permissions('manage_api_keys')
@login_required
def api_keys(service_id):
return render_template(
'views/api/keys.html',
@@ -84,8 +84,8 @@ def api_keys(service_id):
@main.route("/services/<service_id>/api/keys/create", methods=['GET', 'POST'])
@login_required
@user_has_permissions('manage_api_keys', restrict_admin_usage=True)
@login_required
def create_api_key(service_id):
form = CreateKeyForm(current_service.api_keys)
form.key_type.choices = [
@@ -125,8 +125,8 @@ def create_api_key(service_id):
@main.route("/services/<service_id>/api/keys/revoke/<key_id>", methods=['GET', 'POST'])
@login_required
@user_has_permissions('manage_api_keys')
@login_required
def revoke_api_key(service_id, key_id):
key_name = current_service.get_api_key(key_id)['name']
if request.method == 'GET':
@@ -168,8 +168,8 @@ def check_token_against_dummy_bearer(token):
@main.route("/services/<service_id>/api/callbacks", methods=['GET'])
@login_required
@user_has_permissions('manage_api_keys')
@login_required
def api_callbacks(service_id):
if not current_service.has_permission('inbound_sms'):
return redirect(url_for('.delivery_status_callback', service_id=service_id))
@@ -193,8 +193,8 @@ def get_delivery_status_callback_details():
@main.route("/services/<service_id>/api/callbacks/delivery-status-callback", methods=['GET', 'POST'])
@login_required
@user_has_permissions('manage_api_keys')
@login_required
def delivery_status_callback(service_id):
delivery_status_callback = get_delivery_status_callback_details()
back_link = (
@@ -256,8 +256,8 @@ def get_received_text_messages_callback():
@main.route("/services/<service_id>/api/callbacks/received-text-messages-callback", methods=['GET', 'POST'])
@login_required
@user_has_permissions('manage_api_keys')
@login_required
def received_text_messages_callback(service_id):
if not current_service.has_permission('inbound_sms'):
return redirect(url_for('.api_integration', service_id=service_id))