Django

Code

Ticket #3583: modpython.3.py

File modpython.3.py, 5.5 kB (added by Rick van Hattem <Rick.van.Hattem@Fawo.nl>, 2 years ago)

django/contrib/auth/handlers/modpython.py with patches to enable both PythonAuthenHandler? and PythonAccessHandler?

Line 
1 from mod_python import apache
2 import os
3 from urllib import quote
4 from django.core import signals
5 from django.dispatch import dispatcher
6 from django.core.handlers.base import BaseHandler
7 from django.core.handlers.modpython import ModPythonRequest
8 from django.conf import settings
9 from django.contrib.auth import authenticate, REDIRECT_FIELD_NAME
10 from django.utils.encoding import iri_to_uri
11
12 _str_to_bool = lambda s: s.lower() in ('1', 'true', 'on', 'yes')
13
14 class ModPythonAuthOptions:
15     def __init__(self, req):
16         options = req.get_options()
17         self.permission_name = options.get('DjangoPermissionName', None)
18         self.staff_only = _str_to_bool(options.get('DjangoRequireStaffStatus', "on"))
19         self.superuser_only = _str_to_bool(options.get('DjangoRequireSuperuserStatus', "off"))
20         self.raise_forbidden = _str_to_bool(options.get('DjangoRaiseForbidden', "off"))
21         self.settings_module = options.get('DJANGO_SETTINGS_MODULE', None)
22
23 def setup_environment(req, options):
24     """
25     mod_python fakes the environ, and thus doesn't process SetEnv. This ensures
26     any future imports relying on settings will work.
27     """
28     os.environ.update(req.subprocess_env)
29     if options.settings_module:
30         os.environ['DJANGO_SETTINGS_MODULE'] = options.settings_module
31
32 def authenticate_user(user):
33     if user is None:
34         return False
35     if hasattr(user, 'is_authenticated') and not user.is_authenticated():
36         return False
37     return True
38
39 def validate_user(user, options):
40     if hasattr(user, 'is_active') and not user.is_active:
41         return False
42     if options.staff_only and not getattr(user, 'is_staff', None):
43         return False
44     if options.superuser_only and not getattr(user, 'is_superuser', None):
45         return False
46     # If a permission is required then user must have a has_perm function to
47     # validate.
48     if options.permission_name and (not hasattr(user, 'has_perm') or
49                                     not user.has_perm(options.permission_name)):
50         return False
51     return True
52
53 def redirect_to_login(req):
54     path = quote(req.uri)
55     if req.args:
56         path = '%s?%s' % (path, req.args)
57     path = quote(path)
58     iri = '%s?%s=%s' % (settings.LOGIN_URL, REDIRECT_FIELD_NAME, path)
59     uri = iri_to_uri(iri)
60     req.err_headers_out.add('Location', uri)
61     if req.proto_num >= 1001:
62         # Use HTTP Error 303 (see other) for HTTP/1.1 browsers.
63         raise apache.SERVER_RETURN, apache.HTTP_SEE_OTHER
64     else:
65         # Otherwise use HTTP Error 302 (moved temporarily).
66         raise apache.SERVER_RETURN, apache.HTTP_MOVED_TEMPORARILY
67
68 def authenhandler(req, **kwargs):
69     """
70     mod_python authentication handler that checks against Django's auth
71     database.
72     """
73     options = ModPythonAuthOptions(req)
74     setup_environment(req, options)
75
76     dispatcher.send(signal=signals.request_started)
77     try:
78         # This populates req.user too, so it's important to do first.
79         password = req.get_basic_auth_pw()
80
81         # Get the user from any of the installed backends.
82         user = authenticate(username=req.user, password=password)
83
84         if not authenticate_user(user):
85             # Raise unauthorized if the user doesn't authenticate to bring up a
86             # password dialog box to allow the user to authenticate.
87             return apache.HTTP_UNAUTHORIZED
88
89         # Validate the user
90         if validate_user(user, options):
91             return apache.OK
92
93         # mod_python docs say that HTTP_FORBIDDEN should be raised if the user
94         # authenticates but doesn't validate but Django provides it as an
95         # option, alternately raising HTTP_UNAUTHORIZED again to provide the
96         # option of logging in as an alternate user.
97         if options.raise_forbidden:
98             return apache.HTTP_FORBIDDEN
99         else:
100             return apache.HTTP_UNAUTHORIZED   
101     finally:
102         dispatcher.send(signal=signals.request_finished)
103
104 def accesshandler(req):
105     """
106     mod_python access handler that uses the contrib.auth framework (with
107     sessions, therefore requiring a session cookie).
108     """
109     options = ModPythonAuthOptions(req)
110     setup_environment(req, options)
111
112     # Set up middleware, now that settings works we can do it now.
113     base_handler = BaseHandler()
114     base_handler.load_middleware()
115
116     dispatcher.send(signal=signals.request_started)
117     try:
118         request = ModPythonRequest(req)
119
120         # Apply request middleware
121         for middleware_method in base_handler._request_middleware:
122             response = middleware_method(request)
123             if response:
124                 # If we get a response then there's no need to keep processing
125                 # any remaining request middleware.
126                 break
127
128         user = getattr(request, 'user', None)
129         if not authenticate_user(user):
130             # Rather than raising HTTP_UNAUTHORIZED (which the browser won't be
131             # able to handle since this isn't basic HTTP authentication), write
132             # a response which redirects to settings.LOGIN_URL
133             redirect_to_login(req)
134
135         if validate_user(user, options):
136             return apache.OK
137
138         # mod_python docs say that HTTP_FORBIDDEN should be raised if the user
139         # authenticates but doesn't validate but Django provides it as an
140         # option, alternately redirecting to login to provide the option of
141         # logging in as an alternate user.
142         if options.raise_forbidden:
143             return apache.HTTP_FORBIDDEN
144         else:
145             redirect_to_login(req)
146
147     finally:
148         dispatcher.send(signal=signals.request_finished)