Posts tagged ‘python’

Rolling your own authentication in Django

For various reasons I wanted to see just what was required to roll my own basic authentication using Django. I am aware there’s a built-in authentication module, django.contrib.auth, but it’s overkill for my ultimate goal and it depends on the session module in ways that only further study can reveal. I heard rumours that the authentication module would be pluggable. The only pluggable aspect of it that I found was the backend (i.e. the data model).

In the end the most relevant reason for doing this was that I wanted to :-)

So, what’s involved in it? It turns out, not much!

First I created a middleware class that extracts the authentication credentials (read username and password) and sticks a ‘user object’ in the request depending on just how successfully it does this:

from base64 import b64decode
from models import User, AnonUser, BadUser

class MiniAuthMiddleWare(object):
    def process_request(self, request):
        auth = request.META.get('Authorization', '') or \
                request.META.get('HTTP_AUTHORIZATION', '')
        if not auth:
            request.user = AnonUser()
            return

        name, pwd = b64decode(auth[6:]).split(’:')
        try:
            u = User.objects.get(name=name)
            if pwd != u.passwd:
                request.user = BadUser()
                return
            request.user = u
            return
        except User.DoesNotExist, e:
            request.user = BadUser()
        except AssertionError, e:
            request.user = BadUser()

        return

The model related to this is rather minimal:

from django.db import models

class User(models.Model):
    name = models.CharField(maxlength=50, primary_key=True)
    passwd = models.CharField(maxlength=50)

    def is_authenticated(self):
        return True

class AnonUser:
    name = 'Anonymous'
    passwd = 'NoPass'

    def is_authenticated(self):
        return False

class BadUser:
    name = 'BadUser'
    passwd = 'NoPass'

    def is_authenticated(self):
        return False

Then I decorated the functions/urls that required authentication with the following:

def _RequireAuthorization(func):
    def _wrapper(request):
        if not request.user.is_authenticated():
            response = HttpResponse()
            response.status_code = 401
            response['WWW-Authenticate'] = ‘Basic Realm=”Silly Realm”‘
            return response
        else:
            return func(request)
    return _wrapper

That all seems to work just fine :-)

Epilicious is not well

I noticed yesterday that synching was failing due to some bug in pydelicious. That was the last straw and now pydelicious is being chucked out of epilicious. It is a module written by Frank Timmerman, and it can be found here (when it isn’t totally infested with Wiki spam anyway). I was happy to be able to use it for as long as I have since it allowed me to concentrate on other parts of epilicious. Now however epilicious is working fine but pydelicious isn’t. I am not interested in fixing pydelicious since I think it’s a bit of mess and it’d be difficult for me not to do a clean-up at the same time :-) That would most likely take more time than writing something custom made for epilicious.

I’ve written a minimal Python module that offers exactly as much of the del.icio.us API as epilicious needs. If someone’s interested in extending it into a more full-fledged del.icio.us module—be my guest. You can find it in the development BZR repo (libepilicious/delicious.py).

I’ll be making another release of epilicious ASAP.

Jendela - change of implementation language

Unfortunately it seems the Python bindings for wnck aren’t quite up to scratch. I’m getting numerous run-time warnings and sometimes even segmentation faults when doing some stuff (e.g. when shading all windows on the current desktop). I’ve “verified” it’s a problem in the Python binings by hacking together a quick and dirty program in C that does the same thing, with the difference that it doesn’t segfault :-)

It turns out this was just the excuse I needed to take a closer look at the GLib object system and GObject. It was a long time since I wrote anything real in C (experimentation on Windows just doesn’t count) and I’m enjoying myself.

For now the Jendela-in-Python BZR repo is taken down, soon to be replaced by a repo with Jendela-in-C.

Epilicious ready to be localised

The current version in BZR, that’d be version 0.8pre1, has internationalisation support. Currently there’s only one language, Swedish, but I’m looking forward to receiving onther languages to add to the list. (I’m more than happy to receive any pointers regarding the language in epilicious, be it English, Swedish, or any other language.)

The actual implementation was very straight forward, basically I copied what’s in Python’s gettext documentation. I read some other documents as well, just to know what I was getting myself into :) The GNOME developers have two documents worth reading. The first one, internationalising GNOME applications, contains what you need to know about internationalising the different types of source files in a GNOME application. The second contains localisation guidelines for developers, it’s not as technical as the first but it’s a good complement to the first.

CherryPy sessions

I almost started pulling my hair over this. The part of the CherryPy book on sessions said that the following code would turn on sessions in CherryPy 2.1:

cherrypy.config.update({'session_filter.on' : True})

However trying to access session data after that resulted in a “500 Internal Error” page telling me that sessions weren’t enabled. Huh?

Luckliy I found this post on the topic. There’s apparently a typo in the book, the line should read:

cherrypy.config.update({'sessionFilter.on' : True})

Cheetah vs. kid: 1 - 0

I should have spent my Sunday doing a million other things, e.g. trying to clean up muttprint’s build system. Instead I decided to take a quick look at TurboGears and its parts. The Arch packages for it didn’t quite build so I ended up spending some time with CherryPy, Cheetah and Kid. I’m an utter beginner when it comes to “programming the web”, I’ve just never been very interested in it. It might be changing now though :)

CherryPy is truly impressive. A simple Hello World web service hints at just how easy it is to use. It’s written in Python, and it’s very pythonic indeed. However CherryPy isn’t what I wanted to write about. Another area I’ve not looked at is templating systems, I haven’t found a need for it yet. That’s possibly because I’ve never really understood what they are and what they do. That’s changing too.

TurboGears uses Kid so that’s were I started. I downloaded a simple example consisting of two files. The template:

<html>
  <head>
    <title py:content="title">Title</title>
  </head>
  <body>

    <h1 py:content="title">There should be content</h1>

    <ol py:if="title">
      <li py:for="line in lines">
      <span py:replace="line"></span>
      </li>
    </ol>

    <dl>
      <span py:for="n, line in enumerate(lines)" py:omit="">
        <dt py:content="'Line %s' % n"></dt>
        <dd py:content="line"></dd>
      </span>
    </dl>

    <p py:replace="'End of page'+title"></p>

  </body>
</html>

The second file is the CherryPy modules that combines the template with values:

import cherrypy
import kid

class HomePage:

    @cherrypy.expose
    def index(self):
        test = kid.Template(file='kid_test.kid')
        test.title = "Test Kid Page"
        test.lines = ['qwe','asd','zxc']
        return test.serialize(output=’xhtml’)


if __name__ == “__main__”:
    cherrypy.root = HomePage()
    cherrypy.server.start()

This, I think, is rather cool. Very clean, very nice. Still I thought it’d be interesting to take a look at Cheetah (one main reason was that their homepage mentioned that reddit.com, which is funded by Paul Graham, uses it). It was a good decision, I think.

I wrote a Cheetah template producing the same output as the Kid template I downloaded.

<html>
  <head>
    <title>$title</title>
  </head>

  <body>
    <h1>$title</h1>

    <ol>
      #for $l in $lines:
      <li>$l</li>
      #end for
    </ol>

    <dl>
      <span>
        #for $n, $l in $enumerate($lines):
        <dt>Line $n</dt>
        <dd>$l</dd>
        #end for
      </span>
    </dl>

    <p>End of page $title</p>
  </body>
</html>

The matching CherryPy module is very similar to the one above.

import cherrypy
from Cheetah.Template import Template

class HomePage:

    @cherrypy.expose
    def index(self):
        tmpl = Template(file='cheetah_test.html', \
                searchList=[{'title': 'Test Cheetah Page', \
                    'lines': ['qwe', 'asd', 'zxc'],
                    }])
        return str(tmpl)

if __name__ == ‘__main__’:
    cherrypy.root = HomePage()
    cherrypy.server.start()

Now, what do I think? I guess the title of the post betrays my preference ;-)

I spent very little time reading documentation to do this. I needed some help to write the Cheetah template since I had to do it myself. However, I think that if I’d had a Cheetah example and tried to create a matching template using Kid, I wouldn’t be writing this right now. The Kid syntax just seems more confusing to me. I think I’d have to read more documentation as well as spend more time with Kid to reach the same level of confidence I have with Cheetah already after 30 minutes with it.

Now I just need to find some nice little project to verify that my first impressions are correct, both relating to Cheetah and to CherryPy. Any ideas?

Playing with Python and GMail

For a project that I’m considering I’ve spent a few hours looking into using Python to access GMail. There’s a nice Python library called libgmail, but it’s a bit overkill since all I want is to see how many unread emails I have. After a bit of searching I found ot that there’s an atom feed that can be used to do exactly that, https://mail.google.com/mail/feed/atom. It uses basic authentication, your GMail username and password. So, I started looking at Python and HTTP.

urllib2 seemed to fit the bill. It has a class called HTTPBasicAuthHandler to do the authentication and everything. I used the following code (entered in ipython of course):

import urllib2
req = urllib2.Request('https://mail.google.com/mail/feed/atom')
try:
    h = urllib2.urlopen(req)
except IOError, e:
    pass
e.headers['www-authenticate']

It should produce something like 'BASIC realm="New mail feed"'. Now we can do the proper connection, pull down the atom entry. I opted to use elementtree since it’s so easy to use. Here’s the full code I put together for this little experiment:

import urllib2
from elementtree.ElementTree import fromstring

ah = urllib2.HTTPBasicAuthHandler()
ah.add_password('New mail feed', 'https://mail.google.com', \
    'user@gmail.com', 'password')
op = urllib2.build_opener(ah)
urllib2.install_opener(op)
res = urllib2.urlopen('https://mail.google.com/mail/feed/atom')

lines = ''.join(res.readlines())
e = fromstring(lines)
fc = e.find('{http://purl.org/atom/ns#}fullcount')
print 'You have %i unread mail(s) in your GMail account' % int(fc.text)

GConf in Python

It just didn’t feel right to have KeySafe use a Windows-style INI file for its configuration so I started looking into using GConf instead.

There are good introductions to GConf here and here. Translating it all to Python is simple thanks to the brilliant people who gave us Gnome-Python.

I wrote this code for viewing the setting of the desktop background’s filename:

#! /usr/bin/python

import gtk
import gtk.glade
import gconf

class GConfViewer:
    def __init__(self):
        gui = gtk.glade.XML('Viewer/viewer.glade')
        self.entry = gui.get_widget('entry')

        client = gconf.client_get_default()
        client.add_dir('/desktop/gnome/background',
                gconf.CLIENT_PRELOAD_NONE)
        client.notify_add('/desktop/gnome/background/picture_filename',
                self.new_background)
        self.new_background(client)
        gui.get_widget('window').show_all()

    def new_background(self, client, *args, **kwargs):
        filename = client.get_string(
                '/desktop/gnome/background/picture_filename')
        self.entry.set_text(filename)

if __name__ == '__main__':
    GConfViewer()
    gtk.main()

I really like the client-server nature of it. A short explanation:

  1. Get the default GConf client.
  2. Add directories.
  3. Tell it to watch a specific key, specifying a callback method to be called when its value is changed.
  4. Define the callback method.

I also wrote code to change the value of a key:

#! /usr/bin/python

import gconf

def set_bool_key(key):
    client = gconf.client_get_default()
    client.set_bool(key, 1)

if __name__ == '__main__':
    set_bool_key('/desktop/gnome/background/draw_background')

Quite self-explanatory, isn’t it?

The next step in development would be to create a schema for the keys. Both introductions above contain pointers on how to write schemas, for more pointers just take a look in /usr/share/gconf/schemas/. The only problem I ran into was registering the schema. The following commandline does the trick:

GCONF_CONFIG_SOURCE=$(gconftool-2 --get-default-source) \
gconftool-2 --makefile-install-rule keysafe.schemas

Of course the kind Debian developers have done their best to shield packagers from nitty-gritty details. CDBS didn’t just work, it seems to make assumptions about the build system of the package (assuming it’s using auto-tools). Just making sure that the schema ends up in usr/share/gconf/schema during package binary-install, then call dh_gconf -ppackage in binary-post-install/package did the trick.

Portforwarding using Twisted, Python

This is a very short proxy written in Python using Twisted 1.3. It forwards port 1080 to localhost:80.

from twisted.internet import reactor
from twisted.protocols import portforward

def server_dataReceived(self, data):
    print 'Server received data:', data
    portforward.Proxy.dataReceived(self, data)
portforward.ProxyServer.dataReceived = server_dataReceived

def client_dataReceived(self, data):
    print 'Client received data:', data
    portforward.Proxy.dataReceived(self, data)
portforward.ProxyClient.dataReceived = client_dataReceived

reactor.listenTCP(1080, portforward.ProxyFactory('localhost', 80))
reactor.run()

Short and sweet, I think.

NTLM HTTP authentication proxy

I was looking around for a way to get a Python SOAP client to access a web service hosted in such a way that NTLM authentication was needed. Lacking any indication of built in support in SOAPpy to handle this I turned to trusted old Google. I found this, a small NTLM HTTP authentication proxy written in Python.

Configuration was a breeze, After putting in the domain (NT_DOMAIN) and the user (USER), skipping password (PASSWORD) since it can be done interactively it didn’t quite work. I had to tweak the values for LM_PART, NT_PART, and NTLM_FLAGS, setting them to 1, 1, and 07820000 respecitvely.

I performed my testing downloading the WSDL file using wget.