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