Skip to content

Commit

Permalink
Fix order of endpoint decorators
Browse files Browse the repository at this point in the history
Now, the role check of ``admin_required`` is always
performed first.

Closes #1751
  • Loading branch information
Friedrich Weber committed Jul 19, 2019
1 parent b9b2f4f commit c46cca6
Show file tree
Hide file tree
Showing 5 changed files with 54 additions and 21 deletions.
4 changes: 2 additions & 2 deletions privacyidea/api/caconnector.py
Expand Up @@ -59,9 +59,9 @@ def get_caconnector_api(name=None):


@caconnector_blueprint.route('/<name>', methods=['POST'])
@admin_required
@log_with(log)
@prepolicy(check_base_action, request, ACTION.CACONNECTORWRITE)
@admin_required
def save_caconnector_api(name=None):
"""
Create a new CA connector
Expand All @@ -75,9 +75,9 @@ def save_caconnector_api(name=None):


@caconnector_blueprint.route('/<name>', methods=['DELETE'])
@admin_required
@log_with(log)
@prepolicy(check_base_action, request, ACTION.CACONNECTORDELETE)
@admin_required
def delete_caconnector_api(name=None):
"""
Delete a specific CA connector
Expand Down
16 changes: 8 additions & 8 deletions privacyidea/api/system.py
Expand Up @@ -82,8 +82,8 @@


@system_blueprint.route('/documentation', methods=['GET'])
@prepolicy(check_base_action, request, ACTION.CONFIGDOCUMENTATION)
@admin_required
@prepolicy(check_base_action, request, ACTION.CONFIGDOCUMENTATION)
def get_config_documentation():
"""
returns an restructured text document, that describes the complete
Expand Down Expand Up @@ -149,8 +149,8 @@ def get_config(key=None):


@system_blueprint.route('/setConfig', methods=['POST'])
@prepolicy(check_base_action, request, ACTION.SYSTEMWRITE)
@admin_required
@prepolicy(check_base_action, request, ACTION.SYSTEMWRITE)
def set_config():
"""
set a configuration key or a set of configuration entries
Expand Down Expand Up @@ -214,8 +214,8 @@ def set_config():


@system_blueprint.route('/setDefault', methods=['POST'])
@prepolicy(check_base_action, request, ACTION.SYSTEMWRITE)
@admin_required
@prepolicy(check_base_action, request, ACTION.SYSTEMWRITE)
def set_default():
"""
define default settings for tokens. These default settings
Expand Down Expand Up @@ -261,9 +261,9 @@ def set_default():


@system_blueprint.route('/<key>', methods=['DELETE'])
@admin_required
@prepolicy(check_base_action, request, ACTION.SYSTEMDELETE)
@log_with(log)
@admin_required
def delete_config(key=None):
"""
delete a configuration key
Expand All @@ -281,9 +281,9 @@ def delete_config(key=None):


@system_blueprint.route('/hsm', methods=['POST'])
@admin_required
@prepolicy(check_base_action, request, ACTION.SETHSM)
@log_with(log)
@admin_required
def set_security_module():
"""
Set the password for the security module
Expand All @@ -296,8 +296,8 @@ def set_security_module():


@system_blueprint.route('/hsm', methods=['GET'])
@log_with(log)
@admin_required
@log_with(log)
def get_security_module():
"""
Get the status of the security module.
Expand All @@ -310,9 +310,9 @@ def get_security_module():


@system_blueprint.route('/random', methods=['GET'])
@admin_required
@prepolicy(check_base_action, request, action=ACTION.GETRANDOM)
@log_with(log)
@admin_required
def rand():
"""
This endpoint can be used to retrieve random keys from privacyIDEA.
Expand Down Expand Up @@ -341,9 +341,9 @@ def rand():


@system_blueprint.route('/test/<tokentype>', methods=['POST'])
@admin_required
@prepolicy(check_base_action, request, action=ACTION.SYSTEMWRITE)
@log_with(log)
@admin_required
def test(tokentype=None):
"""
The call /system/test/email tests the configuration of the email token.
Expand Down
18 changes: 9 additions & 9 deletions privacyidea/api/token.py
Expand Up @@ -293,10 +293,10 @@ def init():

@token_blueprint.route('/challenges/', methods=['GET'])
@token_blueprint.route('/challenges/<serial>', methods=['GET'])
@admin_required
@prepolicy(check_base_action, request, action=ACTION.GETCHALLENGES)
@event("token_getchallenges", request, g)
@log_with(log)
@admin_required
def get_challenges_api(serial=None):
"""
This endpoint returns the active challenges in the database or returns
Expand Down Expand Up @@ -698,10 +698,10 @@ def set_description_api(serial=None):

@token_blueprint.route('/set', methods=['POST'])
@token_blueprint.route('/set/<serial>', methods=['POST'])
@admin_required
@prepolicy(check_base_action, request, action=ACTION.SET)
@event("token_set", request, g)
@log_with(log)
@admin_required
def set_api(serial=None):
"""
This API is only to be used by the admin!
Expand Down Expand Up @@ -800,11 +800,11 @@ def set_api(serial=None):


@token_blueprint.route('/realm/<serial>', methods=['POST'])
@admin_required
@log_with(log)
@prepolicy(check_max_token_realm, request)
@prepolicy(check_base_action, request, action=ACTION.TOKENREALMS)
@event("token_realm", request, g)
@admin_required
def tokenrealm_api(serial=None):
"""
Set the realms of a token.
Expand Down Expand Up @@ -834,10 +834,10 @@ def tokenrealm_api(serial=None):


@token_blueprint.route('/load/<filename>', methods=['POST'])
@admin_required
@log_with(log)
@prepolicy(check_token_upload, request)
@event("token_load", request, g)
@admin_required
def loadtokens_api(filename=None):
"""
The call imports the given file containing token definitions.
Expand Down Expand Up @@ -939,10 +939,10 @@ def loadtokens_api(filename=None):


@token_blueprint.route('/copypin', methods=['POST'])
@admin_required
@log_with(log)
@prepolicy(check_base_action, request, action=ACTION.COPYTOKENPIN)
@event("token_copypin", request, g)
@admin_required
def copypin_api():
"""
Copy the token PIN from one token to the other.
Expand All @@ -962,10 +962,10 @@ def copypin_api():


@token_blueprint.route('/copyuser', methods=['POST'])
@admin_required
@prepolicy(check_base_action, request, action=ACTION.COPYTOKENUSER)
@event("token_copyuser", request, g)
@log_with(log)
@admin_required
def copyuser_api():
"""
Copy the token user from one token to the other.
Expand Down Expand Up @@ -1021,10 +1021,10 @@ def lost_api(serial=None):


@token_blueprint.route('/getserial/<otp>', methods=['GET'])
@admin_required
@prepolicy(check_base_action, request, action=ACTION.GETSERIAL)
@event("token_getserial", request, g)
@log_with(log)
@admin_required
def get_serial_by_otp_api(otp=None):
"""
Get the serial number for a given OTP value.
Expand Down Expand Up @@ -1075,10 +1075,10 @@ def get_serial_by_otp_api(otp=None):


@token_blueprint.route('/info/<serial>/<key>', methods=['POST'])
@admin_required
@prepolicy(check_base_action, request, action=ACTION.SETTOKENINFO)
@event("token_info", request, g)
@log_with(log)
@admin_required
def set_tokeninfo_api(serial, key):
"""
Add a specific tokeninfo entry to a token. Already existing entries
Expand All @@ -1099,10 +1099,10 @@ def set_tokeninfo_api(serial, key):


@token_blueprint.route('/info/<serial>/<key>', methods=['DELETE'])
@admin_required
@prepolicy(check_base_action, request, action=ACTION.SETTOKENINFO)
@event("token_info", request, g)
@log_with(log)
@admin_required
def delete_tokeninfo_api(serial, key):
"""
Delete a specific tokeninfo entry of a token.
Expand Down
4 changes: 2 additions & 2 deletions privacyidea/api/user.py
Expand Up @@ -108,8 +108,8 @@ def get_users():


@user_blueprint.route('/<resolvername>/<username>', methods=['DELETE'])
@prepolicy(check_base_action, request, ACTION.DELETEUSER)
@admin_required
@prepolicy(check_base_action, request, ACTION.DELETEUSER)
def delete_user(resolvername=None, username=None):
"""
Delete a User in the user store.
Expand All @@ -136,8 +136,8 @@ def delete_user(resolvername=None, username=None):

@user_blueprint.route('', methods=['POST'])
@user_blueprint.route('/', methods=['POST'])
@prepolicy(check_base_action, request, ACTION.ADDUSER)
@admin_required
@prepolicy(check_base_action, request, ACTION.ADDUSER)
def create_user_api():
"""
Create a new user in the given resolver.
Expand Down
33 changes: 33 additions & 0 deletions tests/test_api_caconnector.py
Expand Up @@ -5,6 +5,8 @@
from .base import MyApiTestCase
import json
from privacyidea.lib.caconnector import get_caconnector_list, save_caconnector
from privacyidea.lib.policy import set_policy, SCOPE, ACTION
from privacyidea.lib.error import ERROR


class CAConnectorTestCase(MyApiTestCase):
Expand Down Expand Up @@ -136,3 +138,34 @@ def test_06_delete_caconnector(self):
ca_list = get_caconnector_list()
self.assertEqual(len(ca_list), 1)
self.assertEqual(ca_list[0].get("connectorname"), "con2")

def test_07_caconnector_admin_required(self):
self.authenticate_selfservice_user()

# As a selfservice user, we are not allowed to delete a CA connector
with self.app.test_request_context('/caconnector/con1',
data={},
method='DELETE',
headers={'Authorization': self.at_user}):
res = self.app.full_dispatch_request()
self.assertEquals(res.status_code, 401)
result = json.loads(res.data.decode('utf8')).get("result")
self.assertFalse(result['status'])
self.assertEquals(result['error']['code'], ERROR.AUTHENTICATE_MISSING_RIGHT)
self.assertIn("You do not have the necessary role (['admin']) to access this resource",
result['error']['message'])

# We should get the same error message if a USER policy is defined.
set_policy("user", scope=SCOPE.USER, action=ACTION.AUDIT, realm="")
with self.app.test_request_context('/caconnector/con1',
data={},
method='DELETE',
headers={'Authorization': self.at_user}):
res = self.app.full_dispatch_request()
self.assertEquals(res.status_code, 401)
result = json.loads(res.data.decode('utf8')).get("result")
self.assertFalse(result['status'])
self.assertEquals(result['error']['code'], ERROR.AUTHENTICATE_MISSING_RIGHT)
self.assertIn("You do not have the necessary role (['admin']) to access this resource",
result['error']['message'])

0 comments on commit c46cca6

Please sign in to comment.