45
45
from ivle.webapp.base.plugins import ViewPlugin, PublicViewPlugin
46
46
from ivle.webapp.base.xhtml import XHTMLView, XHTMLErrorView
47
47
from ivle.webapp.errors import HTTPError, Unauthorized, NotFound
48
from ivle.webapp.publisher import Publisher, PublishingError
48
from ivle.webapp.urls import Router, RoutingError
49
49
from ivle.webapp import ApplicationRoot
51
51
config = ivle.config.Config()
53
class ObjectPermissionCheckingPublisher(Publisher):
54
"""A specialised publisher that checks object permissions.
56
This publisher verifies that the user holds any permission at all
57
on the model objects through which the resolution path passes. If
58
no permission is held, resolution is aborted with an Unauthorized
61
IMPORTANT: This does NOT check view permissions. It only checks
62
the objects in between the root and the view, exclusive!
65
def traversed_to_object(self, obj):
66
"""Check that the user has any permission at all over the object."""
67
if (hasattr(obj, 'get_permissions') and
68
len(obj.get_permissions(self.root.user, config)) == 0):
69
# Indicate the forbidden object if this is an admin.
70
if self.root.user and self.root.user.admin:
71
raise Unauthorized('Unauthorized: %s' % obj)
76
def generate_publisher(view_plugins, root, publicmode=False):
53
def generate_router(view_plugins, root):
78
55
Build a Mapper object for doing URL matching using 'routes', based on the
79
56
given plugin registry.
81
r = ObjectPermissionCheckingPublisher(root=root)
83
60
r.add_set_switch('api', 'api')
86
view_attr = 'public_views'
87
forward_route_attr = 'public_forward_routes'
88
reverse_route_attr = 'public_reverse_routes'
91
forward_route_attr = 'forward_routes'
92
reverse_route_attr = 'reverse_routes'
95
62
for plugin in view_plugins:
96
if hasattr(plugin, forward_route_attr):
97
for fr in getattr(plugin, forward_route_attr):
98
# An annotated function can also be passed in directly.
99
if hasattr(fr, '_forward_route_meta'):
100
r.add_forward_func(fr)
104
if hasattr(plugin, reverse_route_attr):
105
for rr in getattr(plugin, reverse_route_attr):
106
# An annotated function can also be passed in directly.
107
if hasattr(rr, '_reverse_route_src'):
108
r.add_reverse_func(rr)
112
if hasattr(plugin, view_attr):
113
for v in getattr(plugin, view_attr):
63
if hasattr(plugin, 'forward_routes'):
64
for fr in plugin.forward_routes:
67
if hasattr(plugin, 'views'):
68
for v in plugin.views:
134
89
if user and user.valid:
137
req.publisher = generate_publisher(
138
config.plugin_index[ViewPlugin],
139
ApplicationRoot(req.config, req.store, req.user),
140
publicmode=req.publicmode)
93
raise NotImplementedError("no public mode with obtrav yet!")
95
req.router = generate_router(config.plugin_index[ViewPlugin],
96
ApplicationRoot(req.config, req.store))
143
obj, viewcls, subpath = req.publisher.resolve(req.uri.decode('utf-8'))
99
obj, viewcls, subpath = req.router.resolve(req.uri.decode('utf-8'))
145
101
# We 404 if we have a subpath but the view forbids it.
146
102
if not viewcls.subpath_allowed and subpath:
191
143
req.store.commit()
193
except Unauthorized, e:
194
# Resolution failed due to a permission check. Display a pretty
195
# error, or maybe a login page.
196
XHTMLView.get_error_view(e)(req, e, req.publisher.root).render(req)
198
except PublishingError, e:
201
if req.user and req.user.admin:
145
except RoutingError, e:
202
147
XHTMLErrorView(req, NotFound('Not found: ' +
203
str(e.args)), e[0]).render(req)
148
str(e.args))).render(req)
205
XHTMLErrorView(req, NotFound(), e[0]).render(req)
150
XHTMLErrorView(req, NotFound()).render(req)
211
154
def handle_unknown_exception(req, exc_type, exc_value, exc_traceback):