diff --git a/src/plone/restapi/services/groups/update.py b/src/plone/restapi/services/groups/update.py index 9d17ebc77c..8148b5f7b7 100644 --- a/src/plone/restapi/services/groups/update.py +++ b/src/plone/restapi/services/groups/update.py @@ -1,5 +1,7 @@ +from AccessControl import getSecurityManager from plone.restapi.deserializer import json_body from plone.restapi.services import Service +from Products.CMFCore.permissions import ManagePortal from Products.CMFCore.utils import getToolByName from zExceptions import BadRequest from zope.component.hooks import getSite @@ -34,6 +36,10 @@ def __init__(self, context, request): super().__init__(context, request) self.params = [] + @property + def is_zope_manager(self): + return getSecurityManager().checkPermission(ManagePortal, self.context) + def publishTraverse(self, request, name): # Consume any path segments after /@groups as parameters self.params.append(name) @@ -54,6 +60,9 @@ def reply(self): data = json_body(self.request) group = self._get_group(self._get_group_id) + if not self.is_zope_manager and "Manager" in group.getRoles(): + return self.reply_no_content(status=403) + if not group: raise BadRequest("Trying to update a non-existing group.") diff --git a/src/plone/restapi/tests/test_services_groups.py b/src/plone/restapi/tests/test_services_groups.py index 848df9351b..4b767daa14 100644 --- a/src/plone/restapi/tests/test_services_groups.py +++ b/src/plone/restapi/tests/test_services_groups.py @@ -44,6 +44,20 @@ def setUp(self): def tearDown(self): self.api_session.close() + def set_siteadm(self): + siteadm_username = "siteadm" + siteadm_password = "siteadmpassword" + api.user.create( + email="siteadm@example.com", + roles=["Site Administrator"], + username=siteadm_username, + password=siteadm_password, + ) + self.api_session = RelativeSession(self.portal_url, test=self) + self.api_session.headers.update({"Accept": "application/json"}) + self.api_session.auth = (siteadm_username, siteadm_password) + transaction.commit() + def test_list_groups(self): response = self.api_session.get("/@groups") @@ -173,3 +187,14 @@ def test_delete_non_existing_group(self): transaction.commit() self.assertEqual(response.status_code, 404) + + def test_siteadm_not_add_user_to_group_with_manager_role(self): + self.set_siteadm() + payload = { + "users": {TEST_USER_ID: True, SITE_OWNER_NAME: False}, + } + self.api_session.patch("/@groups/Administrators", json=payload) + transaction.commit() + + administrators = self.gtool.getGroupById("Administrators") + self.assertNotIn(TEST_USER_ID, administrators.getGroupMemberIds())