As most are aware, Apache is a very modular, highly developer-friendly web server. It still serves more web content worldwide than any other web server. The problem for some is that it is written in C and for you to write custom functionality for Apache, this usually means writing an Apache module in C. What you probably didn't know is that there is an easier way and it is due to mod_python.
mod_python is "an Apache module that embeds the Python interpreter within the server". That is kind of vague, and it's even suggested on the mod_python homepage to read the "Introducing mod_python" article from O'Reilly. To save you the trouble, the important parts in the context we're discussing, mod_python provides the following
- A handler to the Apache request processing phaes, like authentication (authn) and authorization (authz)
- An interface to a subset of the Apache API, which means you can call internal Apache functions from Python
Having access to the internal Apache API, or at least some of it, and being able to handle the Apache phases are the parts we're interested in, since a few of those phases are devoted to authn/authz. Before going into any examples or details on how to use these features for creating your own authn/authz module using mod_python, let's go through a very simple series of steps for hooking mod_python into Apache for your application. (We will not be talking about how to install mod_python since there is a plethora of information about this online.) For this example, we'll get talking about how you could use mod_python to create your own custom authn/authz for Subversion.
Hook mod_python into Apache
As usual, there are many ways to do this but since our example is for authentication/authorizing Subversion access, we'll be putting our mod_python stuff within a standard "Location" block. Here is a simple Location block that we will be starting with:
# Work around authz and SVNListParentPath issue
RedirectMatch ^(/repos)$ $1/
# Enable Subversion logging
CustomLog logs/svn_logfile "%t %u %{SVN-ACTION}e" env=SVN-ACTION
<Location /repos/>
# Enable Subversion
DAV svn
# Directory containing all repository for this path
SVNParentPath /opt/repos/svn
# Enable repository listing when browing the Location root
SVNListParentPath On
# Enable WebDAV automatic versioning
SVNAutoversioning On
# Repository Display Name when browsing with the built-in repository browser
SVNReposName "Your Subversion Repository""
</Location>The Location block above is one of the simplest ways to expose a Subversion repository. As you can see there is no authn/authz stuff in here meaning right now, if you exposed your repositories using this Location block, you'd have free roam to do whatever you wanted to the repositories and their contents. Now...let's update our Location block to have the necessary bits to require Apache authentication and to make our Python script the handler of the authn/authz Apache phases.
# Work around authz and SVNListParentPath issue
RedirectMatch ^(/repos)$ $1/
# Enable Subversion logging
CustomLog logs/svn_logfile "%t %u %{SVN-ACTION}e" env=SVN-ACTION
<Location /repos/>
# Enable Subversion
DAV svn
# Directory containing all repository for this path
SVNParentPath /opt/repos/svn
# Enable repository listing when browing the Location root
SVNListParentPath On
# Enable WebDAV automatic versioning
SVNAutoversioning On
# Repository Display Name when browsing with the built-in repository browser
SVNReposName "Your Subversion Repository""
# Do basic password authentication in the clear
AuthType Basic
# The name of the protected area or "realm"
AuthName "Your Subversion Repository"
# Require authentication
Require valid-user
# Make Apache aware that we want to use mod_python
AddHandler mod_python .py
# Specify the callable object to handle the authn phase
PythonAuthenHandler svnauth
# Specify the callable object to handle the authz phase
PythonAuthzHandler svnauth
# Optionally extend the Python path to locate your callable object
PythonPath "sys.path+['/opt/repos/scripts']"
</Location>To better understand the options for the mod_python directives in the Location block, here are a few direct links within the mod_python documentation:
Alright...now that we have Apache ready to use mod_python, we need to create the script used for auth/authz. Since the PythonAuthenHandler and PythonAuthzHandler just specify a module name, we need to have a file named svnauth.py somewhere on the Python path. We can put it into /opt/repos/scripts since we used the PythonPath directive to updated the Python path to include that directory. Now on to the file's contents.
Since we just specified a module name in the mod_python handler directives, we need to follow a specific naming convention for our handler function names. The convention is that you basically strip off the "Python" part of the handler directive's name, and create a function in your module with that name, all lower case of course, that accepts one argument, the Apache request object. Here is a very simple example of our svnauth.py:
#!/usr/bin/env python # -*-python-*- # # Simple example of using mod_python to handle # Apache's authn and authz phases. from mod_python import apache def authenhandler(req): """This function gets called by mod_python to handle Apache's authentication phase""" return apache.OK def authzhandler(req): """This function gets called by mod_python to handle Apache's authorization phase""" return apache.OK
Pretty simple huh? As the functions stand now, they just return "apache.OK" which instructs Apache that the requested user is authentication and authorized to access the repositories. So...now that you know how to hook up mod_python to handle the Apache phases, like the authentication and authorization phases, where do you go from here? Well, that is up to you. This "article" is only to help get you started. But with me being a nice guy, here are some examples of how you might use this knowledge not only for Subversion but for any Apache-based application where you need to use your own authentication/authorization measures:
- Making web service calls to authenticate/authorize a user
- Implementing single sign on for your application
- Whenever your company stores authn/authz information in a way that is not accessible by conventional Apache modules, like storing your Subversion authz information in a database instead of the typical authz file
The possibilities for using mod_python for authn/authz are endless. Honestly, the possibilities for using mod_python for any of the Apache phases are endless. Sure beats writing C-based Apache modules when it comes to simplicity.
As for what we've learned, I hope that I've taught you enough about mod_python and how it can be used with Apache for creating your own pseudo Apache modules. The example I gave is a real-world example where you can use mod_python to implement your own authn/authz for Subversion but that is just an example. Anywhere Apache is used in your infrastructure, mod_python can be used to make hooking into Apache simple and even provide you the ability to do things that the built-in Apache modules don't provide.


