Ticket #3583: modpython.3.py

File modpython.3.py, 5.5 KB (added by Rick van Hattem <Rick.van.Hattem@…>, 16 years ago)

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

Line 
1from mod_python import apache
2import os
3from urllib import quote
4from django.core import signals
5from django.dispatch import dispatcher
6from django.core.handlers.base import BaseHandler
7from django.core.handlers.modpython import ModPythonRequest
8from django.conf import settings
9from django.contrib.auth import authenticate, REDIRECT_FIELD_NAME
10from django.utils.encoding import iri_to_uri
11
12_str_to_bool = lambda s: s.lower() in ('1', 'true', 'on', 'yes')
13
14class 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
23def 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
32def 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
39def 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
53def 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
68def 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
104def 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)
Back to Top