Open Source Software Technical Articles

Want the Best of the Wazi Blogs Delivered Directly to your Inbox?

Subscribe to Wazi by Email

Your email:

Connect with Us!

Current Articles | RSS Feed RSS Feed

mod_python: More Than Just a CGI/WSGI Alternative

  
  
  

Most people who know about mod_python have run across it in situations when they needed to serve a Python-based application via Apache, like Mercurial or ViewVC.  Actually, mod_python is more than just a CGI/WSGI alternative and is self described as "an Apache module that embeds a Python interpreter into the server."  This means you can use mod_python not only to serve Python-based applications that run faster than traditional CGI, but you can actually use exposed Apache APIs to write full-blown Apache modules using the Python language.  mod_python also includes a number of useful tools, like session management for example, that you get access to as well.  That being said, let's learn more about mod_python by creating a simple application using most of the features that mod_python delivers.

mod_python features


mod_python is actually a suite of tools.  Not only can it emulate a CGI environment and allow you to create Apache modules written in Python, but it also provides tooling for:

 

    • CGI environment (emulated)

    • Access to Apache APIs, filters and handlers

    • Session management

    • Server-side includes

    • Python server pages (Similar to any technology allowing logic and presentation in the same file and evaluated on the server, like Java's JSPs)



As you can see, mod_python provides quite the tool-set to accommodate a very wide range of needs.  To showcase these features, we're going to write a very simple application using as many mod_python features as are available.  We will then wrap up with using a mod_python authentication handler that uses your  Twitter credentials to authenticate yourself for your application.

mod_python handlers


Apache handles requests in phases and mod_python provides you with handlers that allow you to write a Python function that will be used by Apache to handle a phase.  So, if you wanted to have a Python-based authentication implementation for your SCM repository server in order to do fancy things like REST/SOAP/XML-RPC/etc to validate a user's credentials, you could use Python and its PythonAuthenHandler to implement such a thing.  To see this in practice, let's get mod_python hooked up to Apache and using a very simple handler to give us the obligatory "Hello World!"

 

# Load the modules
LoadModule python_module libexec/apache2/mod_python.so

<Location /mod_python_article>
# Tell Apache that mod_python will handle this Location
SetHandler mod_python

# Tell mod_python which module to use for handling requests
PythonHandler olex.publisher

# Fix the Python path to be able to locate our application
PythonPath "[r'/home/jwhitlock/tutorials/mod_python_article/src']+sys.path"
</Location>



The above Apache configuration snippet creates a uri base (mod_python_article) and tells Apache that mod_python will use the PythonHandler handler, which is used to generate content and deliver it to the client.  We also told mod_python which Python module (olex.publisher) would be responsible for handling the request and where to find it using the PythonPath mod_python directive. (Of course, you might need to update your path to be where you extract the sample code to.)

 

from mod_python import apache

def handler(req):
""" This is the controller function that will take a request and writes out the content. """
publish(req, 'Hello from mod_python!', type='text/plain')

return apache.OK

# handler


def publish(req, content, type='text/html'):
""" Helper function that removes some boilerplate when writing content. """
req.content_type = '%s; charset=UTF8' % type
req.write(content, 0)

# publish



mod_python handler implementations will all accept a single argument, an Apache request object.  If you were to restart/start Apache and visit http://hostname/mod_python_article, you'd see "Hello from mod_python!" on your screen.  While this is a very simple example, you should have a good idea of how this will work.  When we need to do something via mod_python, all we have to do is write a handler and hook it up in Apache by registering the handler.  With the wiring taken care of, let's move on to the next feature: Session Management.

 

19a98812-f823-48dc-841e-bf029c63c6d7

 

Session Management


What good would any web-based application be without some session management?  Well thankfully, mod_python provides you with not only generic session management system that will work out of the box but it also gives you the necessary APIs to write your own.  (We will only be demonstrating the built-in session management at this time.)  With session management, we can only prompt you for credentials when you've not already logged in and only show you information about your profile if you've logged in.  Pretty standard stuff, but without an example it might not be useful.  So, below is an example of session management in our application.

 

from mod_python import apache, Session

def handler(req):
""" This is the controller function that will take a request and delegate the
request to some Python function. """
# Create/Get the session
session = Session.Session(req)

if session.is_new():
visit_token = 'for the first time'
else:
visit_token = 'again'

# Save the session
session.save()

publish(req, 'Hello, %s, from mod_python!' % visit_token, type='text/plain')

return apache.OK

# handler


def publish(req, content, type='text/html'):
""" Takes the content and writes it to the client. """
req.content_type = '%s; charset=UTF8' % type
req.write(content, 0)

# publish



With the code above, your first visit should produce "Hello, for the first time, from mod_python!" for the output, while on subsequent visits (like by refreshing the page for now) you should see "Hello, again, from mod_python."  What we'll do after we've designed a login page, in the next section, is have people without a session get prompted for a name of their session so that they can then be redirected to their session information page.  Now that we have session management scaffolding in place, let's wrap a UI around this and see the end result.  To do this, we're going to use mod_python's Python Server Pages.

Python Server Pages


mod_python's Python Server Pages (PSP) are very similar to Java Server Pages in that you have a mix of business logic and presentation mixed together.  Of course you can break this out into a template file for the presentation and a function that populates the template with tokens, but in the end the concept isn't new.  For our example, we'll use PSPs to generate a simple login page that is displayed when you do not have a session, or you have a session and haven't named it yet.  Here is an example of the PSP that is used for the login page:

 

<!-- Below is a PSP hack to avoid mod_python using 'text/plain' for the content type. -->
<% req.content_type = 'text/html' %>


<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Session Information - Login</title>
<!-- The stylesheet for this page is omitted here but is available in the download -->
</head>
<body>
<div id="box">
<h1 class="header">Session Information - Login</h1>
<%=error%>
<form id="login_form" name="login_form" method="POST" action="/mod_python_article">
<ol>
<li>
<label for="session_name">Session name:</label>
<input id="session_name" name="session_name" type="text" value="<%=session_name%>"/>
</li>
<li>
<button id="create" name="create">Create Session</button>
</li>
</ol>
</form>
</div>
</body>
</html>



There isn't much in this post other than the hack to fix a bug in mod_python, and you'll also see a few PSP tags where we'll put the content of an error into the page and the content of the session name into the form.  (These are denoted by the <%=error%> and <%=session_name%> texts respectively.)  A better example is in the PSP template used to display the session information (in the download).  Of course, it might make sense to know how to tell mod_python how to find a template and how to populate it with variables, like error and session_name above.  Here's an example of how to create a template from a file and feed data to it:

data = {'error': '', 'session_name': '',}
template = psp.PSP(req, filename='create_session.tmpl')

template.run(data)


At this point, you really have seen an example of all parts of mod_python.  Here's a summary of the topics we've covered:

 

    • We've see how you can tell mod_python to use a publisher to publish content to the web using mod-python

    • We've seen how to create a session and stuff information into it

    • We've seen how to author a Python Server Page, load its contents from a file and give data to it



As promised, there is one more nifty piece of mod_python that we want to show you: how to use mod_python to write a custom authentication handler for Apache.

mod_python Authentication Handler


Have you ever wanted to have Apache authenticate you in a way that it didn't support?  This is often the case in corporate worlds where people use directory systems like Active Directory and OpenLDAP for user/group/etc. management.  Well, while Apache does have LDAP support available, what if you wanted to authenticate to a system that Apache was unaware of, like authenticating to a third-party application?  Well, below is an example of how you can use Twitter to authenticate users of your Subversion repository, starting with the Apache configuration and ending with the mod_python handler:

<Location /svn/repos>
# Subversion configuration
...

# Authentication setup
AuthType Basic
AuthName "Subversion Repository"

# Require a valid user
Require valid-user

# Make sure to use our authentication
AuthBasicAuthoritative off

# mod_python setup
PythonAuthenHandler olex.twitter_authn
PythonPath "sys.path+['/home/jwhitlock/tutorials/mod_python_article/src']"
</Location>

And below is the mod_python handler:
from mod_python import apache

# python-twitter is required for this example (http://code.google.com/p/python-twitter/)
import sys, twitter, urllib2

def authenhandler(req):
""" Authenticates the user based on their Twitter credentials. """
# As documented in mod_python, before you can successfully call req.user you must call
# req.get_basic_auth_pw().
# http://modpython.org/live/current/doc-html/pyapi-mprequest-mem.html#l2h-124
password = req.get_basic_auth_pw()
username = req.user
api = twitter.Api(username=username, password=password)
response = apache.OK

# Since there is no API to authenticate a user, other than writing one
# let's just call the function that returns the least data
try:
api.GetDirectMessages()
except urllib2.HTTPError, e:
# There are many Twitter failure codes that mean more than authentication
# failure but for brevity, a failure means failed authentication.
response = apache.HTTP_UNAUTHORIZED

req.log_error('[authn] Failure to authenticate: %s' % str(e))
except twitter.TwitterError, e:
response = apache.HTTP_UNAUTHORIZED
except:
import traceback

exception = sys.exc_info()
traceLines = traceback.format_exception(exception[0], exception[1], exception[2])

req.log_error('[authn] Unexpected error authenticating to Twitter')

for line in traceLines:
req.log_error(' %s' % line)

return apache.HTTP_INTERNAL_SERVER_ERROR

return response

Summary


mod_python is an excellent way for people knowledgeable in the Python programming language to secure Apache-served applications/content and to even write your own web-based applications.  Due to time constraints the above code samples are not 100% complete, so we've included a tar file with all of the source code above as well as all of the missing parts complete with documentation on how to run the examples.




This work is licensed under a Creative Commons Attribution 3.0 Unported License
Creative Commons License.

Comments

The particular look-alike timepieces are usually significantly less costly compared to the authentic kinds beneath these kinds of situations, that may expense thousands of money. The values of the exceptional brand names are responsible for the particular spurt regarding look-alike timepieces. Merely have a look at oneself and you also should not necessarily locate look-alike timepieces regarding frequent tends to make. All things considered, the particular craftsmen that are producing these kinds of audemars piguet noble pine ocean going look-alike timepieces furthermore devote plenty of replica hublot. The expenses with the audemars piguet noble pine ocean going timepieces rise when an individual would like level a single replica chanel. These kinds of audemars piguet noble pine ocean going timepieces utilize the identical inside elements the genuine kinds carry out. The sole variation among these kinds of 2.55 chanel handbags and also their particular genuine counterparts will be the covering as well as the switch. Even though the covering with the look-alike timepieces are usually crafted from rare metal likewise metals, the original kinds utilize replica chanel bags. To learn when it is a genuine, the particular diamondchanel replicashaped emblem has to be during the key bottom part area of the Pochette. That acquired the particular stone set up thus about, it was a genuine. My partner and i viewed the particular tie. That seemed a great deal just like cowhide buckskin because it has to be therefore i failed to consider it absolutely was any artificial a single. The particular color around the Monogram layout can be regarding more than common top quality in addition to the the need for stitches came out like we were holding shouting together with top quality precisely the in an identical way because the some other Louis Vuitton replica rolex uk carry out.
Posted @ Thursday, July 17, 2014 9:31 PM by fake chanel
Post Comment
Name
 *
Email
 *
Website (optional)
Comment
 *

Allowed tags: <a> link, <b> bold, <i> italics