forked from mcdonc/bikes
/
app7.py
executable file
·147 lines (134 loc) · 5.16 KB
/
app7.py
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
#!/usr/bin/env python
from pyramid.response import Response
from pyramid.view import view_config
from pyramid.config import Configurator
from pyramid.security import Allow, Authenticated, remember, forget
from pyramid.authentication import AuthTktAuthenticationPolicy
from pyramid.authorization import ACLAuthorizationPolicy
from waitress import serve
class BlogentryViews(object):
def __init__(self, request):
self.request = request
@view_config(route_name='blogentry_show')
def show(self):
return Response('Shown')
@view_config(route_name='blogentry_delete',
permission='delete')
def delete(self):
return Response('Deleted')
@view_config(route_name='login')
def login(self):
userid = self.request.params.get('userid')
headers = remember(self.request, userid)
return Response(
'Logged in as %s' % userid,
headers=headers
)
@view_config(route_name='logout')
def logout(self):
headers = forget(self.request)
return Response(
'Logged out',
headers=headers
)
# [1]
class Resource(object):
def __init__(self, name='', acl=None,
parent=None):
self.children = {}
self.__name__ = name
self.__parent__ = parent
if acl is not None:
self.__acl__ = acl
def add_subresource(self, name, acl=None):
self.children[name] = Resource(
name, acl=acl, parent=self
)
def __getitem__(self, name):
return self.children[name]
def __repr__(self):
return '<Resource named %r at %s>' % (
self.__name__, id(self)
)
# [2]
def root_factory(request):
root = Resource(
'',
acl=[(Allow, 'fred', 'delete')]
)
root.add_subresource(
'1',
acl=[(Allow, Authenticated, 'delete')]
)
return root
if __name__ == '__main__':
authn_policy = AuthTktAuthenticationPolicy('soseekrit')
authz_policy = ACLAuthorizationPolicy()
config = Configurator(
root_factory=root_factory,
authentication_policy=authn_policy,
authorization_policy=authz_policy
)
config.add_route('blogentry_show', '/blog/{id}')
# [3]
config.add_route('blogentry_delete', '/blog/{id}/delete',
traverse='/{id}')
config.add_route('login', '/login')
config.add_route('logout', '/logout')
config.scan()
app = config.make_wsgi_app()
serve(app)
# New outcome: Fred can delete all blog entries. Additionally, any
# authenticated user can delete blog entry named '1'.
#
# New features:
#
# [1] A Resource class. It defines a __getitem__ that allows Pyramid to ask it
# for a child. Instances of Resource also get a __parent__ attribute which
# point at the parent of a resource (another Resource). Resource instances
# may also have an ``__acl__``.
#
# [2] We use a function named root_factory to return the root object, which is
# a Resource instance. Before we return the root object, we give it a
# single child named '1'.
#
# [3] We've added a ``traverse`` argument to the ``add_route`` call for the
# ``blogentry_delete`` route. This argument composes the security traversal
# path for this view. It uses the same pattern language as the route
# pattern, so if the URL is ``/blog/1/delete``, the traversal path will
# be ``/1``.
#
# Noteworthy:
#
# - We did not change our view code at all. The changes we made were made to
# the root factory and to the route associated ``blogentry_delete``.
#
# - Since we now have formed a security tree by returning an object that has
# children from the root factory, and since the ``blogentry_delete`` route
# now traverses the tree when it is matched, we can now protect individual
# URLs differently from each other.
#
# - In the above application, ``/blog/1/delete`` can be executed by an
# authenticated user, but ``/blog/2/delete`` cannot. This is because the
# effective ACL will allow the Authenticated user to delete as the result of
# traversing to ``/1`` because there is such a node in the tree, but there
# isn't any node in the security tree for ``/2`` so the root ACL is the only
# ACL consulted. This is often referred to as "object level security", and
# is often a requirement for CMS-like systems.
#
# - Joe can delete 1 but not 2.
#
# - The ACLAuthorizationPolicy *inherits* ACLs from further down the tree
# unless an explicit Deny is encountered. This means that, since the root
# resource has an __acl__ that says "Allow fred to delete", fred will have
# the delete permission "everywhere" in the tree. Unless fred (or another
# principal possesed by the requesting user) is explicitly denied in an ACL
# somewhere.
#
# - FYI, circref formed but not cleaned up when Resource instances are created
# (a resource points to its parent using ``__parent__`` and the parent points
# at its children via the ``children`` dictionary).
#
# - Note that in a real application, the resource tree would typically be
# persisted somewhere (maybe in a database, or in a pickle), and not
# recomposed on every request.