~azzar1/unity/add-show-desktop-key

« back to all changes in this revision

Viewing changes to ivle/dispatch/__init__.py

  • Committer: William Grant
  • Date: 2009-07-30 08:50:35 UTC
  • mfrom: (1297 ivle)
  • mto: (1294.4.2 ui-the-third)
  • mto: This revision was merged to the branch mainline in revision 1353.
  • Revision ID: grantw@unimelb.edu.au-20090730085035-np5s9ghrgymmya8b
MergeĀ fromĀ trunk.

Show diffs side-by-side

added added

removed removed

Lines of Context:
30
30
import os
31
31
import os.path
32
32
import urllib
33
 
import urlparse
34
33
import cgi
35
34
import traceback
36
35
import logging
45
44
import ivle.webapp.security
46
45
from ivle.webapp.base.plugins import ViewPlugin, PublicViewPlugin
47
46
from ivle.webapp.base.xhtml import XHTMLView, XHTMLErrorView
48
 
from ivle.webapp.errors import BadRequest, HTTPError, NotFound, Unauthorized
 
47
from ivle.webapp.errors import HTTPError, Unauthorized, NotFound
49
48
from ivle.webapp.publisher import Publisher, PublishingError
50
49
from ivle.webapp import ApplicationRoot
51
50
 
52
51
config = ivle.config.Config()
53
52
 
54
 
class ObjectPermissionCheckingPublisher(Publisher):
55
 
    """A specialised publisher that checks object permissions.
56
 
 
57
 
    This publisher verifies that the user holds any permission at all
58
 
    on the model objects through which the resolution path passes. If
59
 
    no permission is held, resolution is aborted with an Unauthorized
60
 
    exception.
61
 
 
62
 
    IMPORTANT: This does NOT check view permissions. It only checks
63
 
    the objects in between the root and the view, exclusive!
64
 
    """
65
 
 
66
 
    def traversed_to_object(self, obj):
67
 
        """Check that the user has any permission at all over the object."""
68
 
        if (hasattr(obj, 'get_permissions') and
69
 
            len(obj.get_permissions(self.root.user, config)) == 0):
70
 
            # Indicate the forbidden object if this is an admin.
71
 
            if self.root.user and self.root.user.admin:
72
 
                raise Unauthorized('Unauthorized: %s' % obj)
73
 
            else:
74
 
                raise Unauthorized()
75
 
 
76
 
 
77
 
def generate_publisher(view_plugins, root, publicmode=False):
 
53
def generate_router(view_plugins, root):
78
54
    """
79
55
    Build a Mapper object for doing URL matching using 'routes', based on the
80
56
    given plugin registry.
81
57
    """
82
 
    r = ObjectPermissionCheckingPublisher(root=root)
 
58
    r = Publisher(root=root)
83
59
 
84
60
    r.add_set_switch('api', 'api')
85
61
 
86
 
    if publicmode:
87
 
        view_attr = 'public_views'
88
 
        forward_route_attr = 'public_forward_routes'
89
 
        reverse_route_attr = 'public_reverse_routes'
90
 
    else:
91
 
        view_attr = 'views'
92
 
        forward_route_attr = 'forward_routes'
93
 
        reverse_route_attr = 'reverse_routes'
94
 
 
95
 
 
96
62
    for plugin in view_plugins:
97
 
        if hasattr(plugin, forward_route_attr):
98
 
            for fr in getattr(plugin, forward_route_attr):
 
63
        if hasattr(plugin, 'forward_routes'):
 
64
            for fr in plugin.forward_routes:
99
65
                # An annotated function can also be passed in directly.
100
66
                if hasattr(fr, '_forward_route_meta'):
101
67
                    r.add_forward_func(fr)
102
68
                else:
103
69
                    r.add_forward(*fr)
104
70
 
105
 
        if hasattr(plugin, reverse_route_attr):
106
 
            for rr in getattr(plugin, reverse_route_attr):
 
71
        if hasattr(plugin, 'reverse_routes'):
 
72
            for rr in plugin.reverse_routes:
107
73
                # An annotated function can also be passed in directly.
108
74
                if hasattr(rr, '_reverse_route_src'):
109
75
                    r.add_reverse_func(rr)
110
76
                else:
111
77
                    r.add_reverse(*rr)
112
78
 
113
 
        if hasattr(plugin, view_attr):
114
 
            for v in getattr(plugin, view_attr):
 
79
        if hasattr(plugin, 'views'):
 
80
            for v in plugin.views:
115
81
                r.add_view(*v)
116
82
 
117
83
    return r
126
92
    # Make the request object into an IVLE request which can be given to views
127
93
    req = Request(apachereq, config)
128
94
 
129
 
    req.publisher = generate_publisher(
130
 
        config.plugin_index[ViewPlugin], ApplicationRoot(req),
131
 
        publicmode=req.publicmode)
 
95
    # Hack? Try and get the user login early just in case we throw an error
 
96
    # (most likely 404) to stop us seeing not logged in even when we are.
 
97
    if not req.publicmode:
 
98
        user = ivle.webapp.security.get_user_details(req)
 
99
 
 
100
        # Don't set the user if it is disabled or hasn't accepted the ToS.
 
101
        if user and user.valid:
 
102
            req.user = user
 
103
 
 
104
    if req.publicmode:
 
105
        raise NotImplementedError("no public mode with obtrav yet!")
 
106
 
 
107
    req.router = generate_router(config.plugin_index[ViewPlugin],
 
108
                                 ApplicationRoot(req.config, req.store))
132
109
 
133
110
    try:
134
 
        obj, viewcls, subpath = req.publisher.resolve(req.uri.decode('utf-8'))
 
111
        obj, viewcls, subpath = req.router.resolve(req.uri.decode('utf-8'))
135
112
        try:
136
113
            # We 404 if we have a subpath but the view forbids it.
137
114
            if not viewcls.subpath_allowed and subpath:
143
120
            # Check that the request (mainly the user) is permitted to access
144
121
            # the view.
145
122
            if not view.authorize(req):
146
 
                # Indicate the forbidden object if this is an admin.
147
 
                if req.user and req.user.admin:
148
 
                    raise Unauthorized('Unauthorized: %s' % view)
149
 
                else:
150
 
                    raise Unauthorized()
151
 
 
152
 
            # Non-GET requests from other sites leave us vulnerable to
153
 
            # CSRFs. Block them.
154
 
            referer = req.headers_in.get('Referer')
155
 
            if (referer is None or
156
 
                urlparse.urlparse(req.headers_in.get('Referer')).netloc !=
157
 
                    req.hostname):
158
 
                if req.method != 'GET' and not view.offsite_posts_allowed:
159
 
                    raise BadRequest(
160
 
                        "Non-GET requests from external sites are forbidden "
161
 
                        "for security reasons.")
162
 
 
 
123
                raise Unauthorized()
163
124
            # Render the output
164
125
            view.render(req)
165
126
        except HTTPError, e:
191
152
            handle_unknown_exception(req, *sys.exc_info())
192
153
            return req.OK
193
154
        else:
194
 
            # Commit the transaction if we have a store open.
195
 
            req.commit()
 
155
            req.store.commit()
196
156
            return req.OK
197
 
    except Unauthorized, e:
198
 
        # Resolution failed due to a permission check. Display a pretty
199
 
        # error, or maybe a login page.
200
 
        XHTMLView.get_error_view(e)(req, e, req.publisher.root).render(req)
201
 
        return req.OK
202
157
    except PublishingError, e:
203
158
        req.status = 404
204
159
 
205
 
        if req.user and req.user.admin:
 
160
        if req.user.admin:
206
161
            XHTMLErrorView(req, NotFound('Not found: ' +
207
162
                                         str(e.args)), e[0]).render(req)
208
163
        else:
209
164
            XHTMLErrorView(req, NotFound(), e[0]).render(req)
210
165
 
211
166
        return req.OK
212
 
    finally:
213
 
        # Make sure we close the store.
214
 
        req.cleanup()
215
167
 
216
168
def handle_unknown_exception(req, exc_type, exc_value, exc_traceback):
217
169
    """
227
179
    logfile = os.path.join(config['paths']['logs'], 'ivle_error.log')
228
180
    logfail = False
229
181
 
230
 
    req.status = mod_python.apache.HTTP_INTERNAL_SERVER_ERROR
 
182
    # XXX: This remains here for ivle.interpret's IVLEErrors. Once we rewrite
 
183
    #      fileservice, req.status should always be 500 (ISE) here.
 
184
    try:
 
185
        httpcode = exc_value.httpcode
 
186
        req.status = httpcode
 
187
    except AttributeError:
 
188
        httpcode = None
 
189
        req.status = mod_python.apache.HTTP_INTERNAL_SERVER_ERROR
231
190
 
232
191
    try:
233
192
        publicmode = req.publicmode