summaryrefslogtreecommitdiff
path: root/src/zope/security/interfaces.py
blob: 81addc2e5c283604c3fa8cb77030b3335f5ba3b2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
##############################################################################
#
# 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.
"""

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):
    pass

@implementer(IUnauthorized)
class Unauthorized(Exception):
    """Some user wasn't allowed to access a resource"""

class IForbidden(IException):
    pass

@implementer(IForbidden)
class Forbidden(Exception):
    """A resource cannot be accessed under any circumstances
    """

class IForbiddenAttribute(IForbidden, IAttributeError):
    pass

@implementer(IForbiddenAttribute)
class ForbiddenAttribute(Forbidden, AttributeError):
    """An attribute is unavailable because it is forbidden (private)
    """


class ISecurityManagement(Interface):
    """Public security management API."""

    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.

        'permission' is permission name.

        'object' is the object being accessed according to the permission.

        'interaction' is an interaction, providing access to information
        such as authenticated principals.  If it is None, the current
        interaction is used.
        """


class ISecurityProxyFactory(Interface):

    def __call__(object, checker=None):
        """Create a security proxy

        If a checker 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 check_getattr() and check_setattr() methods for checking
    getattr and setattr, and a check() method for all other operations.

    The check methods may raise errors.  They return no value.

    Example (for __getitem__):

           checker.check(ob, \"__getitem__\")
           return checker.proxy(ob[key])
    """

    def check_getattr(ob, name):
        """Check whether attribute access is allowed.

        May raise Unauthorized or Forbidden.  Returns no value.

        If a checker implements __setitem__, then __setitem__ will be
        called rather than check_getattr to check whether an attribute
        access 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.
        """

    def check_setattr(ob, name):
        """Check whether attribute assignment is allowed.

        May raise Unauthorized or Forbidden.  Returns no value.
        """

    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 check 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.
        """

    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 check and check_getattr.
        """

    def setattr_permission_id(name):
        """Return the permission used to check attribute assignment on name.

        This permission is used by check_setattr.
        """


class ISecurityPolicy(Interface):

    def __call__(participation=None):
        """Creates a new interaction 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.

        Arguments:
        permission -- A permission name
        object -- The object being accessed according to the permission
        """


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.
    """

    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. We'll probably want to
    define a standard view name (e.g.  'inline_summary') for this
    purpose.
    """

    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 group information.
    """

    groups = Attribute(
        'An iterable of groups to which the principal directly belongs')

class IGroupClosureAwarePrincipal(IGroupAwarePrincipal):

    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)