Django

Code

Ticket #3583: apache_auth.patch

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

    old new  
    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 PythonOption
    14     _str_to_bool = lambda s: s.lower() in ('1', 'true', 'on', 'yes'
     59        # Get the user from any of the installed backend
     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

    old new  
    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: