From b453aa4babafa9e6875f89e7cb967ba9dfcbd06e Mon Sep 17 00:00:00 2001 From: wesleybl Date: Thu, 21 Sep 2023 15:49:37 -0300 Subject: [PATCH] Does not allow a Site Administrator delete Manager --- src/plone/restapi/services/users/add.py | 1 - src/plone/restapi/services/users/delete.py | 19 ++++++++++++++++--- .../restapi/tests/test_services_users.py | 9 +++++++++ 3 files changed, 25 insertions(+), 4 deletions(-) diff --git a/src/plone/restapi/services/users/add.py b/src/plone/restapi/services/users/add.py index 151a15708f..1ed8ef45d3 100644 --- a/src/plone/restapi/services/users/add.py +++ b/src/plone/restapi/services/users/add.py @@ -14,7 +14,6 @@ from zope.component import getAdapter from zope.component import getMultiAdapter from zope.component import queryMultiAdapter -from zope.component.hooks import getSite from zope.i18n import translate from zope.interface import alsoProvides from zope.interface import implementer diff --git a/src/plone/restapi/services/users/delete.py b/src/plone/restapi/services/users/delete.py index e7517f6655..b393f817c7 100644 --- a/src/plone/restapi/services/users/delete.py +++ b/src/plone/restapi/services/users/delete.py @@ -1,4 +1,6 @@ +from AccessControl import getSecurityManager from plone.restapi.services import Service +from Products.CMFCore.permissions import ManagePortal from Products.CMFCore.utils import getToolByName from zope.component.hooks import getSite from zope.interface import implementer @@ -15,6 +17,11 @@ class UsersDelete(Service): def __init__(self, context, request): super().__init__(context, request) self.params = [] + self.portal_membership = getToolByName(context, "portal_membership") + + @property + def is_zope_manager(self): + return getSecurityManager().checkPermission(ManagePortal, self.context) def publishTraverse(self, request, name): # Consume any path segments after /@users as parameters @@ -27,9 +34,15 @@ def _get_user_id(self): raise Exception("Must supply exactly one parameter (user id)") return self.params[0] + def _get_user(self, user_id): + return self.portal_membership.getMemberById(user_id) + def reply(self): - portal = getSite() - portal_membership = getToolByName(portal, "portal_membership") + if not self.is_zope_manager: + user = self._get_user(self._get_user_id) + current_roles = user.getRoles() + if "Manager" in current_roles: + return self.reply_no_content(status=403) delete_memberareas = ( self.request.get("delete_memberareas", True) not in FALSE_VALUES @@ -39,7 +52,7 @@ def reply(self): self.request.get("delete_localroles", True) not in FALSE_VALUES ) - delete_successful = portal_membership.deleteMembers( + delete_successful = self.portal_membership.deleteMembers( (self._get_user_id,), delete_memberareas=delete_memberareas, delete_localroles=delete_localroles, diff --git a/src/plone/restapi/tests/test_services_users.py b/src/plone/restapi/tests/test_services_users.py index 4f1c5b86cb..fce04b276c 100644 --- a/src/plone/restapi/tests/test_services_users.py +++ b/src/plone/restapi/tests/test_services_users.py @@ -1354,3 +1354,12 @@ def test_manager_update_manager(self): noam = api.user.get(userid="noam") self.assertIn("Manager", noam.getRoles()) + + def test_siteadm_not_delete_manager(self): + self.set_siteadm() + api.user.grant_roles(username="noam", roles=["Manager"]) + transaction.commit() + self.api_session.delete("/@users/noam") + transaction.commit() + + self.assertIsNotNone(api.user.get(userid="noam"))