apache authentication via cookies

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
import os
from mod_python import apache
from django.core.handlers.base import BaseHandler
from django.core.handlers.modpython import ModPythonRequest

class AccessHandler(BaseHandler):
    def __call__(self, req):
        from django.conf import settings
        # set up middleware
        if self._request_middleware is None:
            self.load_middleware()
	# populate the request object
	request = ModPythonRequest(req)
	# and apply the middleware to it
	# actually only session and auth middleware would be needed here
	for middleware_method in self._request_middleware:
		middleware_method(request)
	return request

def accesshandler(req):
    os.environ.update(req.subprocess_env)
    
    # check for PythonOptions
    _str_to_bool = lambda s: s.lower() in ('1', 'true', 'on', 'yes')

    options = req.get_options()
    permission_name = options.get('DjangoPermissionName', None)
    staff_only = _str_to_bool(options.get('DjangoRequireStaffStatus', "on"))
    superuser_only = _str_to_bool(options.get('DjangoRequireSuperuserStatus', "off"))
    settings_module = options.get('DJANGO_SETTINGS_MODULE', None)
    
    if settings_module:
        os.environ['DJANGO_SETTINGS_MODULE'] = settings_module
    
    request=AccessHandler()(req)
    if request.user.is_authenticated():
	if superuser_only and request.user.is_superuser:
	    return apache.OK
	elif staff_only and request.user.is_staff:
	    return apache.OK
	elif permission_name and request.user.has_perm(permission_name):
	    return apache.OK
    return apache.HTTP_UNAUTHORIZED

More like this

  1. Custom mod_python AuthenHandler by aeby 6 years, 8 months ago
  2. SWFUpload auth decorator by debrice 5 years, 2 months ago
  3. YUI Loader as Django middleware by akaihola 6 years ago
  4. Copy media files to central location for easier sharing by jtiai 4 years, 11 months ago
  5. Functional Filters by waterson 6 years, 6 months ago

Comments

andybak (on May 7, 2007):

I assume this requires mod_python rather than say fcgi?

#

sean (on May 9, 2007):

Yes, wouldn't know how to do this with fcgi. It would probably depend on which server you are using, and how you are able to define handlers for that server.

#

cwurld (on May 19, 2007):

Hi - Thanks for the snippet! Its a real lifesaver for me.

I had to make a few modifications to get it to work for me. First "request.user.is_authenticated()" always comes back as true. I am using IE7 with cookies that expire when the browser window is closed. I solved the problem with the following code:

if request.user.is_anonymous(): return apache.HTTP_UNAUTHORIZED

added before request.user.is_authenticated().

Next, I am using the code to server static pages through apache. In my httpd.conf file, when I had the line:

SetHandler python-program

The requested ended up being served by django. I was able to get apache to serve the content by replacing that line with:

SetHandler None

My (noob) understanding of apache is that it processes the request in phases and the phase called "handler" is the last phase in the sequence. So the python access handler still gets called, but after that the request processing is completed by apache.

Chuck

#

wolf905 (on August 9, 2008):

Thanks for this snippet. I have one comment, which I hope will save some other folks time. Initially, I had this in my httpd.conf:

<Location "/">
    SetHandler python-program
    PythonHandler django.core.handlers.modpython
    SetEnv DJANGO_SETTINGS_MODULE django.settings
    PythonPath "['/path/to/django/project/']  + sys.path"
</Location>
<Location "/media">
    SetHandler none
</Location>
<Location "/media/reciprocals">
        PythonPath "['/path/to/django/project/'] + sys.path"
        PythonOption DJANGO_SETTINGS_MODULE django.settings
        PythonOption DjangoPermissionName 'django.permission'
        PythonAccessHandler django.apache_accesshandler
        SetHandler None
</Location>

Which threw this lovely error:

    File "/usr/lib/python2.4/os.py", line 463, in __setitem__
    putenv(key, item)

TypeError: putenv() argument 2 must be string, not list

I figured out that somehow multiple req objects were being processed by the handler at the same time, thus giving me multiple copies of the environment. I fixed this by rearranging my Location directives as so:

<Location "/media/reciprocals">
        PythonPath "['/path/to/django/project/'] + sys.path"
        PythonOption DJANGO_SETTINGS_MODULE django.settings
        PythonOption DjangoPermissionName 'django.permission'
        PythonAccessHandler django.apache_accesshandler
        SetHandler None
</Location>
<Location "/media">
    SetHandler none
</Location>
<Location "/">
    SetHandler python-program
    PythonHandler django.core.handlers.modpython
    SetEnv DJANGO_SETTINGS_MODULE django.settings
    PythonPath "['/path/to/django/project/']  + sys.path"
</Location>

I'm not familiar at all with the way apache works with mod_python, but this reconfiguration of my httpd.conf makes things work as I expect them to. So I hope this helps save someone else some frustration.

-Pat

#

(Forgotten your password?)