| 1 | from mod_python import apache
|
|---|
| 2 | import os
|
|---|
| 3 | from django.core import signals
|
|---|
| 4 | from django.dispatch import dispatcher
|
|---|
| 5 | from django.core.handlers.base import BaseHandler
|
|---|
| 6 | from django.core.handlers.modpython import ModPythonRequest
|
|---|
| 7 | from django.contrib.auth import authenticate
|
|---|
| 8 |
|
|---|
| 9 | _str_to_bool = lambda s: s.lower() in ('1', 'true', 'on', 'yes')
|
|---|
| 10 |
|
|---|
| 11 | class ModPythonAuthOptions:
|
|---|
| 12 | def __init__(self, req):
|
|---|
| 13 | options = req.get_options()
|
|---|
| 14 | self.permission_name = options.get('DjangoPermissionName', None)
|
|---|
| 15 | self.staff_only = _str_to_bool(options.get('DjangoRequireStaffStatus', "on"))
|
|---|
| 16 | self.superuser_only = _str_to_bool(options.get('DjangoRequireSuperuserStatus', "off"))
|
|---|
| 17 | self.settings_module = options.get('DJANGO_SETTINGS_MODULE', None)
|
|---|
| 18 |
|
|---|
| 19 | def setup_environment(req, options):
|
|---|
| 20 | """
|
|---|
| 21 | mod_python fakes the environ, and thus doesn't process SetEnv. This ensures
|
|---|
| 22 | any future imports relying on settings will work.
|
|---|
| 23 | """
|
|---|
| 24 | os.environ.update(req.subprocess_env)
|
|---|
| 25 | if options.settings_module:
|
|---|
| 26 | os.environ['DJANGO_SETTINGS_MODULE'] = options.settings_module
|
|---|
| 27 |
|
|---|
| 28 | def authenticate_user(user, options):
|
|---|
| 29 | if not user:
|
|---|
| 30 | return False
|
|---|
| 31 | # Require an is_authenticated property and check it
|
|---|
| 32 | if not hasattr(user, 'is_authenticated') or not user.is_authenticated():
|
|---|
| 33 | return False
|
|---|
| 34 | return True
|
|---|
| 35 |
|
|---|
| 36 | def validate_user(user, options):
|
|---|
| 37 | # Don't require an is_active property, but if it's there then check it
|
|---|
| 38 | if hasattr(user, 'is_active') and not user.is_active:
|
|---|
| 39 | return False
|
|---|
| 40 | if options.staff_only and not getattr(user, 'is_staff', None):
|
|---|
| 41 | return False
|
|---|
| 42 | if options.superuser_only and not getattr(user, 'is_superuser', None):
|
|---|
| 43 | return False
|
|---|
| 44 | # If a permission is required then user must have a has_perm function to validate
|
|---|
| 45 | if options.permission_name and (not hasattr(user, 'has_perm') or not user.has_perm(options.permission_name)):
|
|---|
| 46 | return False
|
|---|
| 47 | return True
|
|---|
| 48 |
|
|---|
| 49 | def authenhandler(req, **kwargs):
|
|---|
| 50 | """
|
|---|
| 51 | mod_python authentication handler that checks against Django's auth
|
|---|
| 52 | database.
|
|---|
| 53 | """
|
|---|
| 54 | options = ModPythonAuthOptions(req)
|
|---|
| 55 | setup_environment(req, options)
|
|---|
| 56 |
|
|---|
| 57 | dispatcher.send(signal=signals.request_started)
|
|---|
| 58 | try:
|
|---|
| 59 | # This populates req.user too, so it's important to do first
|
|---|
| 60 | password = req.get_basic_auth_pw()
|
|---|
| 61 |
|
|---|
| 62 | # Get the user from any of the installed backends
|
|---|
| 63 | user = authenticate(username=req.user, password=password)
|
|---|
| 64 |
|
|---|
| 65 | # Raise unauthorized if the user wasn't authenticated to bring up
|
|---|
| 66 | # a password dialog box to allow the user to authenticate.
|
|---|
| 67 |
|
|---|
| 68 | # Check authentification of the user
|
|---|
| 69 | if not authenticate_user(user, options):
|
|---|
| 70 | return apache.HTTP_UNAUTHORIZED
|
|---|
| 71 |
|
|---|
| 72 | # Validate and check permission of the user
|
|---|
| 73 | if validate_user(user, options):
|
|---|
| 74 | return apache.OK
|
|---|
| 75 | else:
|
|---|
| 76 | # mod_python docs say that HTTP_FORBIDDEN should be raised if the
|
|---|
| 77 | # user authenticates but doesn't validate.
|
|---|
| 78 | return apache.HTTP_FORBIDDEN
|
|---|
| 79 | finally:
|
|---|
| 80 | dispatcher.send(signal=signals.request_finished)
|
|---|
| 81 |
|
|---|
| 82 | def accesshandler(req):
|
|---|
| 83 | """
|
|---|
| 84 | mod_python access handler that uses the contrib.auth framework (with
|
|---|
| 85 | sessions and therefore requiring a session cookie).
|
|---|
| 86 | """
|
|---|
| 87 | options = ModPythonAuthOptions(req)
|
|---|
| 88 | setup_environment(req, options)
|
|---|
| 89 |
|
|---|
| 90 | # Set up middleware, now that settings works we can do it now.
|
|---|
| 91 | base_handler = BaseHandler()
|
|---|
| 92 | base_handler.load_middleware()
|
|---|
| 93 |
|
|---|
| 94 | dispatcher.send(signal=signals.request_started)
|
|---|
| 95 | try:
|
|---|
| 96 | request = ModPythonRequest(req)
|
|---|
| 97 |
|
|---|
| 98 | # Apply request middleware
|
|---|
| 99 | for middleware_method in base_handler._request_middleware:
|
|---|
| 100 | response = middleware_method(request)
|
|---|
| 101 | if response:
|
|---|
| 102 | # If we get a response, we should probably stop processing any
|
|---|
| 103 | # remaining request middleware.
|
|---|
| 104 | break
|
|---|
| 105 |
|
|---|
| 106 | # get user object
|
|---|
| 107 | user = getattr(request, 'user', None)
|
|---|
| 108 |
|
|---|
| 109 | # Check authentification of the user
|
|---|
| 110 | if not authenticate_user(user, options):
|
|---|
| 111 | return apache.HTTP_UNAUTHORIZED
|
|---|
| 112 |
|
|---|
| 113 | # Validate and check permission of the user
|
|---|
| 114 | if validate_user(user, options):
|
|---|
| 115 | return apache.OK
|
|---|
| 116 | else:
|
|---|
| 117 | # mod_python docs say that HTTP_FORBIDDEN should be raised if the
|
|---|
| 118 | # user authenticates but doesn't validate.
|
|---|
| 119 | return apache.HTTP_FORBIDDEN
|
|---|
| 120 |
|
|---|
| 121 | finally:
|
|---|
| 122 | dispatcher.send(signal=signals.request_finished)
|
|---|