############################################################################## # # Copyright (c) 2004 Zope Foundation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ Interfaces for security machinery. These can be categorized into a few different groups of related objects. * Exceptions - :class:`IUnauthorized` - :class:`IForbidden` - :class:`IForbiddenAttribute` - :class:`NoInteraction` * Utilities - :class:`ISecurityManagement` - :class:`ISecurityChecking` - :class:`ISecurityProxyFactory` - :class:`IChecker` - :class:`INameBasedChecker` - :class:`ISecurityPolicy` * Principals - :class:`IInteraction` - :class:`IParticipation` - :class:`IInteractionManagement` - :class:`IPrincipal` - :class:`IGroupAwarePrincipal` - :class:`IGroupClosureAwarePrincipal` - :class:`IGroup` - :class:`IMemberGetterGroup` - :class:`IMemberAwareGroup` - :class:`IPermission` """ from zope.interface import Interface, Attribute, implementer from zope.interface.common.interfaces import IException, IAttributeError from zope.schema import Text, TextLine from zope.security.i18n import ZopeMessageFactory as _ #: The name (id) of the registered :class:`IPermission` utility that signifies #: that the protected attribute is public. #: #: .. versionadded:: 4.2.0 PUBLIC_PERMISSION_NAME = 'zope.Public' class IUnauthorized(IException): """ The action is not authorized. Implemented in :class:`Unauthorized`. """ @implementer(IUnauthorized) class Unauthorized(Exception): """ Some user wasn't allowed to access a resource. Default implementation of :class:`IUnauthorized`. """ class IForbidden(IException): """ A resource cannot be accessed under any circumstances Implemented in :class:`Forbidden`. """ @implementer(IForbidden) class Forbidden(Exception): """ A resource cannot be accessed under any circumstances Default implementation if :class:`IForbidden`. """ class IForbiddenAttribute(IForbidden, IAttributeError): """ An attribute is unavailable because it is forbidden (private). Implemented in :class:`ForbiddenAttribute`. """ @implementer(IForbiddenAttribute) class ForbiddenAttribute(Forbidden, AttributeError): """ An attribute is unavailable because it is forbidden (private). Default implementation of :class:`IForbiddenAttribute`. """ class ISecurityManagement(Interface): """ Public security management API. This is implemented by :mod:`zope.security.management`. """ def getSecurityPolicy(): """Get the system default security policy.""" def setSecurityPolicy(aSecurityPolicy): """Set the system default security policy. This method should only be called by system startup code. It should never, for example, be called during a web request. """ class ISecurityChecking(Interface): """ Public security API. """ def checkPermission(permission, object, interaction=None): """ Return whether security policy allows permission on object. :param str permission: The permission name. :param object: The object being accessed according to the permission. :keyword interaction: An :class:`IInteraction`, providing access to information such as authenticated principals. If it is None, the current interaction is used. """ class ISecurityProxyFactory(Interface): """ A factory for creating security-proxied objects. See :class:`zope.security.checker.ProxyFactory` for the default implementation. """ def __call__(object, checker=None): """ Create a security proxy If a checker (:class:`IChecker`) is given, then use it, otherwise, try to figure out a checker. If the object is already a security proxy, then it will be returned. """ class IChecker(Interface): """ Security-proxy plugin objects that implement low-level checks. The checker is responsible for creating proxies for operation return values, via the ``proxy`` method. There are :meth:`check_getattr` and :meth:`check_setattr` methods for checking getattr and setattr, and a :meth:`check` method for all other operations. The check methods will raise errors if access is not allowed. They return no value. Example (for ``__getitem__``):: checker.check(ob, "__getitem__") return checker.proxy(ob[key]) .. seealso:: :mod:`zope.security.checker` """ def check_getattr(ob, name): """ Check whether attribute access is allowed. If a checker implements ``__setitem__``, then ``__setitem__`` will be called rather than ``check`` to ascertain whether an operation is allowed. This is a hack that allows significantly greater performance due to the fact that low-level operator access is much faster than method access. :raises: :class:`Unauthorized` :raises: :class:`Forbidden` :return: Nothing """ def check_setattr(ob, name): """ Check whether attribute assignment is allowed. If a checker implements ``__setitem__``, then ``__setitem__`` will be called rather than ``check`` to ascertain whether an operation is allowed. This is a hack that allows significantly greater performance due to the fact that low-level operator access is much faster than method access. :raises: :class:`Unauthorized` :raises: :class:`Forbidden` :return: Nothing """ def check(ob, operation): """ Check whether *operation* is allowed. The operation name is the Python special method name, e.g. "__getitem__". May raise Unauthorized or Forbidden. Returns no value. If a checker implements ``__setitem__``, then ``__setitem__`` will be called rather than ``check`` to ascertain whether an operation is allowed. This is a hack that allows significantly greater performance due to the fact that low-level operator access is much faster than method access. :raises: :class:`Unauthorized` :raises: :class:`Forbidden` :return: Nothing """ def proxy(value): """ Return a security proxy for the *value*. If a checker implements ``__getitem__``, then ``__getitem__`` will be called rather than ``proxy`` to proxy the value. This is a hack that allows significantly greater performance due to the fact that low-level operator access is much faster than method access. """ class INameBasedChecker(IChecker): """ Security checker that uses permissions to check attribute access. """ def permission_id(name): """ Return the permission used to check attribute access on *name*. This permission is used by both :meth:`check` and :meth:`check_getattr`. """ def setattr_permission_id(name): """ Return the permission used to check attribute assignment on *name*. This permission is used by :meth:`check_setattr`. """ class ISecurityPolicy(Interface): """ A factory to get :class:`IInteraction` objects. .. seealso:: :mod:`zope.security.simplepolicies` For default implementations. """ def __call__(participation=None): """ Creates and returns a new :class:`IInteraction` for a given request. If *participation* is not None, it is added to the new interaction. """ class IInteraction(Interface): """ A representation of an interaction between some actors and the system. """ participations = Attribute("""An iterable of participations.""") def add(participation): """Add a participation.""" def remove(participation): """Remove a participation.""" def checkPermission(permission, object): """Return whether security context allows permission on object. :param str permission: A permission name :param object: The object being accessed according to the permission :return: Whether the access is allowed or not. :rtype: bool """ class IParticipation(Interface): interaction = Attribute("The interaction") principal = Attribute("The authenticated principal") class NoInteraction(Exception): """No interaction started """ class IInteractionManagement(Interface): """ Interaction management API. Every thread has at most one active interaction at a time. .. seealso:: :mod:`zope.security.management` That module provides the default implementation. """ def newInteraction(participation=None): """ Start a new interaction. If *participation* is not None, it is added to the new interaction. Raises an error if the calling thread already has an interaction. """ def queryInteraction(): """ Return the current interaction. Return None if there is no interaction. """ def getInteraction(): """ Return the current interaction. :raise NoInteraction: if there isn't a current interaction. """ def endInteraction(): """ End the current interaction. Does nothing if there is no interaction. """ class IPrincipal(Interface): """ Principals are security artifacts that execute actions in a security environment. The most common examples of principals include user and group objects. It is likely that ``IPrincipal`` objects will have associated views used to list principals in management interfaces. For example, a system in which other meta-data are provided for principals might extend ``IPrincipal`` and register a view for the extended interface that displays the extended information. """ id = TextLine( title=_("Id"), description=_("The unique identification of the principal."), required=True, readonly=True) title = TextLine( title=_("Title"), description=_("The title of the principal. " "This is usually used in the UI."), required=False) description = Text( title=_("Description"), description=_("A detailed description of the principal."), required=False) class IGroupAwarePrincipal(IPrincipal): """ Group aware principal interface. Extends ``IPrincipal`` to contain direct group information. """ groups = Attribute( 'An iterable of :class:`IGroup` objects to which the principal directly belongs') class IGroupClosureAwarePrincipal(IGroupAwarePrincipal): """ A group-aware principal that can recursively flatten the membership of groups to return all the groups. """ allGroups = Attribute( "An iterable of the full closure of the principal's groups.") class IGroup(IPrincipal): """ Group of principals """ class IMemberGetterGroup(IGroup): """ A group that can get its members. """ def getMembers(): """Return an iterable of the members of the group""" class IMemberAwareGroup(IMemberGetterGroup): """ A group that can both set and get its members. """ def setMembers(value): """ Set members of group to the principal ids in the iterable *value*. """ class IPermission(Interface): """A permission object.""" id = TextLine( title=_("Id"), description=_("Id as which this permission will be known and used."), readonly=True, required=True) title = TextLine( title=_("Title"), description=_("Provides a title for the permission."), required=True) description = Text( title=_("Description"), description=_("Provides a description for the permission."), required=False)