diff --git a/ckan/ckanext/ckanext-restricteddata/ckanext/restricteddata/logic/auth.py b/ckan/ckanext/ckanext-restricteddata/ckanext/restricteddata/logic/auth.py index 578b9159..35046b9e 100644 --- a/ckan/ckanext/ckanext-restricteddata/ckanext/restricteddata/logic/auth.py +++ b/ckan/ckanext/ckanext-restricteddata/ckanext/restricteddata/logic/auth.py @@ -29,6 +29,15 @@ def member_delete(next_auth: AuthFunction, context: Context, data_dict: DataDict return next_auth(context, data_dict) +@toolkit.chained_auth_function +def member_list(next_auth: AuthFunction, context: Context, data_dict: DataDict) -> AuthResult: + match data_dict['object_type']: + case 'user': + return sysadmin_only(context, data_dict) + + return next_auth(context, data_dict) + + def sysadmin_only(contaxt, data_dict): return {'success': False, 'message': 'Only sysadmins are allowed to call this'} diff --git a/ckan/ckanext/ckanext-restricteddata/ckanext/restricteddata/plugin.py b/ckan/ckanext/ckanext-restricteddata/ckanext/restricteddata/plugin.py index 15da5edc..08cef6eb 100644 --- a/ckan/ckanext/ckanext-restricteddata/ckanext/restricteddata/plugin.py +++ b/ckan/ckanext/ckanext-restricteddata/ckanext/restricteddata/plugin.py @@ -217,6 +217,9 @@ def get_auth_functions(self): return { 'member_create': auth.member_create, 'member_delete': auth.member_delete, + 'member_list': auth.member_list, + 'organization_member_create': auth.sysadmin_only, + 'organization_member_list': auth.sysadmin_only, 'api_token_create': auth.sysadmin_only, 'user_list': auth.sysadmin_only } diff --git a/ckan/ckanext/ckanext-restricteddata/ckanext/restricteddata/tests/test_plugin.py b/ckan/ckanext/ckanext-restricteddata/ckanext/restricteddata/tests/test_plugin.py index 4b928183..a067df8f 100644 --- a/ckan/ckanext/ckanext-restricteddata/ckanext/restricteddata/tests/test_plugin.py +++ b/ckan/ckanext/ckanext-restricteddata/ckanext/restricteddata/tests/test_plugin.py @@ -51,7 +51,7 @@ def test_some_action(): import datetime from ckan.plugins import plugin_loaded, toolkit -from ckan.tests.factories import Dataset, Sysadmin, Organization, User, Group +from ckan.tests.factories import Dataset, Sysadmin, Organization, User, Group, APIToken from ckan.tests.helpers import call_action from ckan.plugins.toolkit import NotAuthorized from .utils import (minimal_dataset, minimal_dataset_with_one_resource_fields, @@ -713,3 +713,22 @@ def test_only_sysadmin_can_manage_organization_members(): # Verify another_user is not in organization members members = call_action('member_list', id=organization["id"], object_type="user", capacity="member") assert all(member_id != another_user["id"] for member_id, _, _ in members) + + +@pytest.mark.usefixtures("with_plugins", "clean_db") +def test_normal_user_has_no_access_to_organization_member_edit_pages(app): + user = User() + organization = Organization(user=user, **minimal_organization()) + client = app.test_client(use_cookies=True) + headers = {"Authorization": APIToken(user=user['name'])["token"]} + + # Make sure the user has admin privileges to the organization + result = client.get(toolkit.url_for("organization.edit", id=organization['name']), headers=headers) + assert result.status_code == 200 + + # Verify the user cannot view the member edit pages + result = client.get(toolkit.url_for("organization.member_new", id=organization['name']), headers=headers) + assert result.status_code == 403 + + result = client.get(toolkit.url_for("organization.members", id=organization['name']), headers=headers) + assert result.status_code == 403