Ticket #3583: apache_auth.patch

File apache_auth.patch, 7.2 KB (added by SmileyChris, 8 years ago)
  • django/contrib/auth/handlers/modpython.py

     
    11from mod_python import apache
    22import os
     3from django.core import signals
     4from django.dispatch import dispatcher
     5from django.core.handlers.base import BaseHandler
     6from django.core.handlers.modpython import ModPythonRequest
     7from django.contrib.auth import authenticate
    38
     9_str_to_bool = lambda s: s.lower() in ('1', 'true', 'on', 'yes')
     10
     11class 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
     19def 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
     28def validate_user(user, options):
     29    if not user:
     30        return False
     31    # Don't require an is_authenticated property, but if it's there then check it
     32    if hasattr(user, 'is_authenticated') and not user.is_authenticated():
     33        return False
     34    # Don't require an is_active property, but if it's there then check it
     35    if hasattr(user, 'is_active') and not user.is_active:
     36        return False
     37    if options.staff_only and not getattr(user, 'is_staff', None):
     38        return False
     39    if options.superuser_only and not getattr(user, 'is_superuser', None):
     40        return False
     41    # If a permission is required then user must have a has_perm function to validate
     42    if options.permission_name and (not hasattr(user, 'has_perm') or not user.has_perm(self.permission_name)):
     43        return False
     44    return True
     45
    446def authenhandler(req, **kwargs):
    547    """
    6     Authentication handler that checks against Django's auth database.
     48    mod_python authentication handler that checks against Django's auth
     49    database.
    750    """
     51    options = ModPythonAuthOptions(req)
     52    setup_environment(req, options)
    853
    9     # mod_python fakes the environ, and thus doesn't process SetEnv.  This fixes
    10     # that so that the following import works
    11     os.environ.update(req.subprocess_env)
     54    dispatcher.send(signal=signals.request_started)
     55    try:
     56        # This populates req.user too, so it's important to do first
     57        password = req.get_basic_auth_pw()
    1258
    13     # check for PythonOptions
    14     _str_to_bool = lambda s: s.lower() in ('1', 'true', 'on', 'yes')
     59        # Get the user from any of the installed backends
     60        user = authenticate(username=req.user, password=password)
    1561
    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
     62        # Validate the user
     63        if validate_user(user, options):
     64            return apache.OK
     65        else:
     66            return apache.HTTP_UNAUTHORIZED
     67    finally:
     68        dispatcher.send(signal=signals.request_finished)
    2369
    24     from django.contrib.auth.models import User
    25     from django import db
    26     db.reset_queries()
     70def accesshandler(req):
     71    """
     72    mod_python access handler that uses the contrib.auth framework (with
     73    sessions and therefore requiring a session cookie).
     74    """
     75    options = ModPythonAuthOptions(req)
     76    setup_environment(req, options)
    2777
    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
     78    # Set up middleware, now that settings works we can do it now.
     79    base_handler = BaseHandler()
     80    base_handler.load_middleware()
     81
     82    dispatcher.send(signal=signals.request_started)
    3483    try:
    35         try:
    36             user = User.objects.get(**kwargs)
    37         except User.DoesNotExist:
    38             return apache.HTTP_UNAUTHORIZED
    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
     84        request = ModPythonRequest(req)
     85
     86        # Apply request middleware
     87        for middleware_method in base_handler._request_middleware:
     88            response = middleware_method(request)
     89            if response:
     90                # If we get a response, we should probably stop processing any
     91                # remaining request middleware.
     92                break
     93
     94        # Validate the user
     95        user = getattr(request, 'user', None)
     96        if validate_user(user, options):
     97            return apache.OK
    4998        else:
    50             return apache.HTTP_UNAUTHORIZED
     99            return apache.HTTP_FORBIDDEN
    51100    finally:
    52         db.connection.close()
     101        dispatcher.send(signal=signals.request_finished)
  • docs/apache_auth.txt

     
    1717==================
    1818
    1919To check against Django's authorization database from a Apache configuration
    20 file, you'll need to use mod_python's ``PythonAuthenHandler`` directive along
     20file, you can either use mod_python's ``PythonAuthenHandler`` directive along
    2121with the standard ``Auth*`` and ``Require`` directives::
    2222
    2323    <Location /example/>
     
    2929        PythonAuthenHandler django.contrib.auth.handlers.modpython
    3030    </Location>
    3131
     32... or use mod_python's ``PythonAccessHandler`` directive::
     33
     34    <Location /example/>
     35        SetEnv DJANGO_SETTINGS_MODULE mysite.settings
     36        PythonAccessHandler django.contrib.auth.handlers.modpython
     37    </Location>
     38
     39The difference between these two methods is that ``PythonAuthenHandler`` uses
     40basic HTTP authentication where as ``PythonAccessHandler`` uses the built-in
     41``contrib.auth`` authentication (which uses a session cookie).
     42
     43``PythonAuthenHandler`` will prompt the user to enter their user name and
     44password (usually via a basic authentication dialog box), while
     45``PythonAccessHandler`` will simply raise an Apache "Forbidden" error if the
     46user is not logged in or does not have the correct authorization.
     47
    3248By default, the authentication handler will limit access to the ``/example/``
    3349location to users marked as staff members.  You can use a set of
    3450``PythonOption`` directives to modify this behavior:
Back to Top