source: package_branches/invirt-web/cherrypy/code/view.py @ 2531

Last change on this file since 2531 was 2531, checked in by quentin, 15 years ago

Revert "Replace weird username logic with the old logic."

This reverts r2519. The "weird username logic" is in fact correctly
implementing the documented CherryPy? authentication API.

File size: 5.7 KB
RevLine 
[2485]1import os, sys
[2385]2
3import cherrypy
4from mako.template import Template
5from mako.lookup import TemplateLookup
6import simplejson
7import datetime, decimal
[2485]8from StringIO import StringIO
[2397]9from invirt.config import structs as config
[2399]10from webcommon import State
[2385]11
12class MakoHandler(cherrypy.dispatch.LateParamPageHandler):
13    """Callable which sets response.body."""
14   
15    def __init__(self, template, next_handler, content_type='text/html; charset=utf-8'):
16        self.template = template
17        self.next_handler = next_handler
18        self.content_type = content_type
19   
20    def __call__(self):
21        env = globals().copy()
22        env.update(self.next_handler())
23        cherrypy.response.headers['Content-Type'] = self.content_type
24        return self.template.render(**env)
25       
26
27class MakoLoader(object):
28   
29    def __init__(self):
30        self.lookups = {}
[2485]31
32    def get_lookup(self, directories, module_directory=None,
33                     collection_size=-1, imports=[], **kwargs):
[2385]34        # Find the appropriate template lookup.
35        key = (tuple(directories), module_directory)
36        try:
37            lookup = self.lookups[key]
38        except KeyError:
39            lookup = TemplateLookup(directories=directories,
40                                    module_directory=module_directory,
41                                    collection_size=collection_size,
42                                    default_filters=['decode.utf8'],
43                                    input_encoding='utf-8',
44                                    output_encoding='utf-8',
[2402]45                                    imports=imports,
[2385]46                                    )
47            self.lookups[key] = lookup
[2485]48        return lookup
49
50    def __call__(self, filename, directories, module_directory=None,
51                 collection_size=-1, content_type='text/html; charset=utf-8',
52                 imports=[]):
53        cherrypy.request.lookup = lookup = self.get_lookup(directories, module_directory,
54                                                           collection_size, imports)
[2385]55        cherrypy.request.template = t = lookup.get_template(filename)
56        cherrypy.request.handler = MakoHandler(t, cherrypy.request.handler, content_type)
57
[2518]58cherrypy.tools.mako = cherrypy.Tool('on_start_resource', MakoLoader())
[2385]59
[2485]60def revertStandardError():
61    """Move stderr to stdout, and return the contents of the old stderr."""
62    errio = sys.stderr
63    if not isinstance(errio, StringIO):
64        return ''
65    sys.stderr = sys.stdout
66    errio.seek(0)
67    return errio.read()
68
69def catchStderr():
70    old_handler = cherrypy.request.handler
71    def wrapper(*args, **kwargs):
72        sys.stderr = StringIO()
73        ret = old_handler(*args, **kwargs)
74        e = revertStandardError()
75        if e:
76            if isinstance(ret, dict):
77                ret["error_text"] = e
78        return ret
79    if old_handler:
80        cherrypy.request.handler = wrapper
81
82cherrypy.tools.catch_stderr = cherrypy.Tool('before_handler', catchStderr)
83
[2385]84class JSONEncoder(simplejson.JSONEncoder):
85        def default(self, obj):
86                if isinstance(obj, datetime.datetime):
87                        return str(obj)
88                elif isinstance(obj, decimal.Decimal):
89                        return float(obj)
90                else:
91                        return simplejson.JSONEncoder.default(self, obj)
92
93def jsonify_tool_callback(*args, **kwargs):
94    if not cherrypy.request.cached:
95        response = cherrypy.response
96        response.headers['Content-Type'] = 'text/javascript'
97        response.body = JSONEncoder().iterencode(response.body)
98
99cherrypy.tools.jsonify = cherrypy.Tool('before_finalize', jsonify_tool_callback, priority=30)
100
[2391]101def require_login():
102    """If the user isn't logged in, raise 403 with an error."""
[2531]103    if cherrypy.request.login is False:
[2391]104        raise cherrypy.HTTPError(403,
105            "You are not authorized to access that resource")
106
[2397]107cherrypy.tools.require_login = cherrypy.Tool('on_start_resource', require_login, priority=150)
[2391]108
[2422]109def require_POST():
110    """If the request isn't a POST request, raise 405 Method Not Allowed"""
111    if cherrypy.request.method != "POST":
112        raise cherrypy.HTTPError(405,
113                                 "You must submit this request with POST")
114
115cherrypy.tools.require_POST = cherrypy.Tool('on_start_resource', require_POST, priority=150)
116
[2397]117def remote_user_login():
[2531]118    """Get the current user based on the SSL or GSSAPI environment
119variables and store it in the request object's login variable. This
120conforms to the CherryPy API:
121http://www.cherrypy.org/wiki/RequestObject#login
122
123If the user is logged in successfully, cherrypy.request.login is set
124to the username. If the user failed to log in, cherrypy.request.login
125is set to False. If the user did not attempt authentication,
126cherrypy.request.login is set to None."""
[2397]127    environ = cherrypy.request.wsgi_environ
128    user = environ.get('REMOTE_USER')
129    if user is None:
130        return
[2531]131    else:
132        cherrypy.request.login = None # clear what cherrypy put there
[2397]133
134    if environ.get('AUTH_TYPE') == 'Negotiate':
135        # Convert the krb5 principal into a krb4 username
136        if not user.endswith('@%s' % config.kerberos.realm):
[2531]137            cherrypy.request.login = False # failed to login
[2397]138        else:
139            cherrypy.request.login = user.split('@')[0].replace('/', '.')
140    else:
141        cherrypy.request.login = user
142
143cherrypy.tools.remote_user_login = cherrypy.Tool('on_start_resource', remote_user_login, priority=50)
144
[2399]145def invirtwebstate_init():
146    """Initialize the cherrypy.request.state object from Invirt"""
[2482]147    if not hasattr(cherrypy.request, "state"):
148        cherrypy.request.state = State(cherrypy.request.login)
[2399]149
150cherrypy.tools.invirtwebstate = cherrypy.Tool('on_start_resource', invirtwebstate_init, priority=100)
151
[2385]152class View(object):
153    _cp_config = {'tools.mako.directories': [os.path.join(os.path.dirname(__file__),'templates')]}
Note: See TracBrowser for help on using the repository browser.