| 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) |