provides software and services that enable enterprises
Live Chat 1-888-673-6564

Open Source Software Technical Articles

  • Home
  • Search
  • Contact Us
  • Products and Support
  • Services
  • Enterprise OSS Blog
  • Wazi Technical Blog
  • About Wazi
  • Attributions and Licensing
  • Supply Chain Compliance
  • How to Contribute
  • Contributors
  • Resources Library
  • Cloud Services
  • Partners
  • Customers
  • Community
  • Company
  • Careers
  • News and Events

Subscribe to Wazi by Email

Your email:


Enterprise Developer Support 24 x 7, Get a Support Quote Now!


click-here-to-chat-with-an-online-representative

download-oss-discovery

Latest Posts

  • A more colorful LibreOffice unveiled
  • Toward a more colorful LibreOffice
  • Flexible administration with Puppet's Facter and templates
  • Knock for OpenSSH
  • Get more out of phpMyAdmin
  • Image annotation in GIMP, Dia, and OpenOffice Draw
  • Solr, Drupal 7, and faceted search
  • Using FreeNAS' new full disk encryption for ZFS
  • Create distributed storage with Gluster
  • How to set up Solr 4.2 on Drupal 7 with Apache

Connect with Us!

Current Articles | RSS Feed RSS Feed

mod_python: More Than Just a CGI/WSGI Alternative

Posted by Jeremy Whitlock on Thu, Aug 19, 2010
  
Email This Email Article  
Tweet  
  

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.

Follow @openlogic
Follow @OSCloudServices

This work is licensed under a Creative Commons Attribution 3.0 Unported License
Creative Commons License.
Tags: Subversion, Apache, Python, Technical, Tutorial, Web Server, ViewVC, Mercurial, OpenLDAP, mod_python

Comments

Currently, there are no comments. Be the first to post one!
Post Comment
Name
 *
Email
 *
Website (optional)
Comment
 *

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

Loading...
Error sending email
Email sent successfully

Email article
Email To : 
Your name : 
Message : (maximum 200 characters)
Home | Search | Contact Us | Products and Support | Services | Enterprise OSS Blog | Wazi Technical Blog | Resources Library | Cloud Services | Partners | Customers | Community | Company | Careers | News and Events
Products
OpenLogic Exchange (OLEX)
License Compliance Module
OSS Discovery
OSS Deep Discovery
OpenUpdate
Services
Open Source Support
CentOS Support
Scanning & Compliance
Open Source Training
Professional Services
Solutions
Support & Indemnification
Open Source Governance
Open Source Scanning
Open Source Provisioning
Consulting & Training
Contact Us
1-888-673-6564


© 2013 OpenLogic, Inc. All rights reserved.
Site Map  |  Privacy Policy