# HG changeset patch # User Thierry Florac # Date 1435669327 -7200 # Node ID b999bd4dd461b8bd02eed3b04d9fc12cf84a6259 # Parent d2ee97ff6d3eb4a65a3d198cf41d067705bf18a3 Added properties to security manager to correctly handle denied permissions diff -r d2ee97ff6d3e -r b999bd4dd461 src/pyams_security/interfaces/__init__.py --- a/src/pyams_security/interfaces/__init__.py Wed Jun 17 09:59:26 2015 +0200 +++ b/src/pyams_security/interfaces/__init__.py Tue Jun 30 15:02:07 2015 +0200 @@ -714,14 +714,26 @@ required=True, default=True) - everyone_permissions = PermissionsSetField(title=_("Public permissions"), - description=_("These permissions will be granted to all users"), + everyone_denied = PermissionsSetField(title=_("Public denied permissions"), + description=_("These permissions will be denied to all users. " + "Denied permissions take precedence over granted " + "ones."), + required=False) + + everyone_granted = PermissionsSetField(title=_("Public granted permissions"), + description=_("These permissions will be granted to all users"), + required=False) + + authenticated_denied = PermissionsSetField(title=_("Authenticated denied permissions"), + description=_("These permissions will be denied to " + "authenticated users. Denied permissions " + "take precedence over granted ones."), required=False) - authenticated_permissions = PermissionsSetField(title=_("Authenticated permissions"), - description=_("These permissions will be granted to authenticated " - "users"), - required=False) + authenticated_granted = PermissionsSetField(title=_("Authenticated granted permissions"), + description=_("These permissions will be granted to authenticated " + "users"), + required=False) inherit_parent_roles = Bool(title=_("Inherit parent roles?"), description=_("Get roles granted on parent levels"), @@ -749,6 +761,21 @@ def get_permissions(self, principal_id): """Get ID of permissions granted to given principal""" + def get_everyone_denied(self): + """Get denied permissions for everyone, including inherited ones""" + + def get_everyone_granted(self): + """Get granted permissions for everyone, including inherited ones""" + + def get_authenticated_denied(self): + """Get denied permissions for authenticated, including inherited ones""" + + def get_authenticated_granted(self): + """Get granted permissions for authenticated, including inherited ones""" + + def get_granted_roles(self): + """Get all roles, including inherited ones""" + class IRoleProtectedObject(IProtectedObject): """Roles protected object interface""" diff -r d2ee97ff6d3e -r b999bd4dd461 src/pyams_security/security.py --- a/src/pyams_security/security.py Wed Jun 17 09:59:26 2015 +0200 +++ b/src/pyams_security/security.py Tue Jun 30 15:02:07 2015 +0200 @@ -28,7 +28,7 @@ from pyams_utils.property import request_property from pyams_utils.registry import query_utility from pyramid.location import lineage -from pyramid.security import DENY_ALL, Everyone, Allow, ALL_PERMISSIONS, Authenticated +from pyramid.security import DENY_ALL, Everyone, Allow, Deny, ALL_PERMISSIONS, Authenticated from pyramid.threadlocal import get_current_registry from zope.container.contained import Contained from zope.interface import implementer @@ -42,49 +42,59 @@ """Base class for object protected by roles""" inherit_parent_security = FieldProperty(IRoleProtectedObject['inherit_parent_security']) - _everyone_permissions = FieldProperty(IRoleProtectedObject['everyone_permissions']) - _authenticated_permissions = FieldProperty(IRoleProtectedObject['authenticated_permissions']) + everyone_denied = FieldProperty(IRoleProtectedObject['everyone_denied']) + everyone_granted = FieldProperty(IRoleProtectedObject['everyone_granted']) + authenticated_denied = FieldProperty(IRoleProtectedObject['authenticated_denied']) + authenticated_granted = FieldProperty(IRoleProtectedObject['authenticated_granted']) inherit_parent_roles = FieldProperty(IRoleProtectedObject['inherit_parent_roles']) def __init__(self): self._principals_by_role = PersistentDict() self._roles_by_principal = PersistentDict() - @property - def everyone_permissions(self): - permissions = self._everyone_permissions - if (not permissions) and self.inherit_parent_security: + def get_everyone_denied(self): + permissions = self.everyone_denied or set() + if self.inherit_parent_security: + for parent in lineage(self): + if parent in (self, self.__parent__): + continue + protection = IProtectedObject(parent, None) + if protection is not None: + permissions = permissions | (protection.everyone_denied or set()) + return permissions + + def get_everyone_granted(self): + permissions = self.everyone_granted or set() + if self.inherit_parent_security: for parent in lineage(self): if parent in (self, self.__parent__): continue protection = IProtectedObject(parent, None) if protection is not None: - permissions = protection.everyone_permissions - if permissions: - break + permissions = permissions | (protection.everyone_granted or set()) return permissions - @everyone_permissions.setter - def everyone_permissions(self, value): - self._everyone_permissions = value - - @property - def authenticated_permissions(self): - permissions = self._authenticated_permissions - if (not permissions) and self.inherit_parent_security: + def get_authenticated_denied(self): + permissions = self.authenticated_denied or set() + if self.inherit_parent_security: for parent in lineage(self): if parent in (self, self.__parent__): continue protection = IProtectedObject(parent, None) if protection is not None: - permissions = protection.authenticated_permissions - if permissions: - break + permissions = permissions | (protection.authenticated_denied or set()) return permissions - @authenticated_permissions.setter - def authenticated_permissions(self, value): - self._authenticated_permissions = value + def get_authenticated_granted(self): + permissions = self.authenticated_granted or set() + if self.inherit_parent_security: + for parent in lineage(self): + if parent in (self, self.__parent__): + continue + protection = IProtectedObject(parent, None) + if protection is not None: + permissions = permissions | (protection.authenticated_granted or set()) + return permissions def grant_role(self, role_id, principal_ids): registry = get_current_registry() @@ -146,24 +156,43 @@ result |= role.permissions or set() return result + def get_granted_roles(self): + roles = set(self._principals_by_role.keys()) + if self.inherit_parent_roles: + for parent in lineage(self): + if parent in (self, self.__parent__): + continue + protection = IProtectedObject(parent, None) + if protection is not None: + roles = roles | protection.get_granted_roles() + return roles + @request_property(key=None) def __acl__(self): # always grant all permissions to system manager result = [(Allow, 'system:admin', ALL_PERMISSIONS)] - # grant permission to everyone and authenticated - if self.everyone_permissions: - result.append((Allow, Everyone, self.everyone_permissions)) - if self.authenticated_permissions: - result.append((Allow, Authenticated, self.authenticated_permissions)) # grant access to all roles permissions - for role_id in self._principals_by_role.keys(): + for role_id in self.get_granted_roles(): role = query_utility(IRole, role_id) if role is not None: result.append((Allow, 'role:{0}'.format(role_id), role.permissions)) + # grant permission to everyone and authenticated + permissions = self.get_everyone_denied() + if permissions: + result.append((Deny, Everyone, permissions)) + permissions = self.get_authenticated_denied() + if permissions: + result.append((Deny, Authenticated, permissions)) + permissions = self.get_authenticated_granted() + if permissions: + result.append((Allow, Authenticated, permissions)) + permissions = self.get_everyone_granted() + if permissions: + result.append((Allow, Everyone, permissions)) # stop inheritance if required if not self.inherit_parent_security: result.append(DENY_ALL) - logger.debug('ACL = {0}'.format(str(result))) + logger.debug('ACL({0!r}) = {1}'.format(self.__parent__, str(result))) return result diff -r d2ee97ff6d3e -r b999bd4dd461 src/pyams_security/zmi/security.py --- a/src/pyams_security/zmi/security.py Wed Jun 17 09:59:26 2015 +0200 +++ b/src/pyams_security/zmi/security.py Tue Jun 30 15:02:07 2015 +0200 @@ -83,12 +83,6 @@ edit_permission = 'security.manage' weight = 1 - def updateWidgets(self, prefix=None): - super(ProtectedObjectSecuritySubform, self).updateWidgets() - translate = self.request.localizer.translate - self.widgets['everyone_permissions'].noValueMessage = translate(_("(inherit from parent)")) - self.widgets['authenticated_permissions'].noValueMessage = translate(_("(inherit from parent)")) - @adapter_config(name='roles.subform', context=(IDefaultProtectionPolicy, IPyAMSLayer, ProtectedObjectRolesEditForm), diff -r d2ee97ff6d3e -r b999bd4dd461 src/pyams_security/zmi/utility.py --- a/src/pyams_security/zmi/utility.py Wed Jun 17 09:59:26 2015 +0200 +++ b/src/pyams_security/zmi/utility.py Tue Jun 30 15:02:07 2015 +0200 @@ -151,9 +151,6 @@ table_class = SecurityManagerPluginsTable - def __init__(self, context, request): - super(SecurityManagerView, self).__init__(context, request) - @adapter_config(context=(ISite, IAdminLayer, SecurityManagerView), provides=IPageHeader) class SecurityManagerHeaderAdapter(DefaultPageHeaderAdapter): @@ -202,7 +199,7 @@ def update(self): super(SecurityManagerEditForm, self).update() - self.add_group(NamedWidgetsGroup('social_group', self.widgets, + self.add_group(NamedWidgetsGroup(self, 'social_group', self.widgets, ('enable_social_login', 'social_users_folder', 'authomatic_secret', 'social_login_use_popup'), legend=_("Enable social login?"), @@ -210,14 +207,14 @@ switch=True, checkbox_switch=True, checkbox_field=ISecurityManager['enable_social_login'])) - self.add_group(NamedWidgetsGroup('registry_group', self.widgets, + self.add_group(NamedWidgetsGroup(self, 'registry_group', self.widgets, ('open_registration', 'users_folder'), legend=_("Enable free registration?"), css_class='inner', switch=True, checkbox_switch=True, checkbox_field=ISecurityManager['open_registration'])) - plugins_group = NamedWidgetsGroup('plugins_group', self.widgets, + plugins_group = NamedWidgetsGroup(self, 'plugins_group', self.widgets, ('credentials_plugins_names', 'authentication_plugins_names', 'directory_plugins_names'), legend=_("Plug-ins"),