4 | | def authenhandler(req, **kwargs): |
| 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): |
16 | | options = req.get_options() |
17 | | permission_name = options.get('DjangoPermissionName', None) |
18 | | staff_only = _str_to_bool(options.get('DjangoRequireStaffStatus', "on")) |
19 | | superuser_only = _str_to_bool(options.get('DjangoRequireSuperuserStatus', "off")) |
20 | | settings_module = options.get('DJANGO_SETTINGS_MODULE', None) |
21 | | if settings_module: |
22 | | os.environ['DJANGO_SETTINGS_MODULE'] = settings_module |
| 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 |
24 | | from django.contrib.auth.models import User |
25 | | from django import db |
26 | | db.reset_queries() |
| 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 |
28 | | # check that the username is valid |
29 | | kwargs = {'username': req.user, 'is_active': True} |
30 | | if staff_only: |
31 | | kwargs['is_staff'] = True |
32 | | if superuser_only: |
33 | | kwargs['is_superuser'] = True |
| 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) |
35 | | try: |
36 | | user = User.objects.get(**kwargs) |
37 | | except User.DoesNotExist: |
| 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. |
39 | | |
40 | | # check the password and any permission given |
41 | | if user.check_password(req.get_basic_auth_pw()): |
42 | | if permission_name: |
43 | | if user.has_perm(permission_name): |
44 | | return apache.OK |
45 | | else: |
46 | | return apache.HTTP_UNAUTHORIZED |
47 | | else: |
48 | | return apache.OK |
| 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 |
52 | | db.connection.close() |
| 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) |