20
Jan

Two-step authentication with Django

A quick post on django-twostepauth, a package I helped develop. This is a package that enables Django to use token devices for user authentication, like for example the free Google Authenticator available for many mobile phones.

I've been using the two-step token authentication on my gmail account and that reduced my fear of having my email account cracked. I hope other websites, yes I'm thinking of you home banking, start to allow this kind of protection.

If you do not know what two-step authentication is, the video below gives a quick tour of the authentication using the example application shipped with this django package.



The package should be easy to integrate with any website. You can download it from the usual place, or clone it from the repository. As always, feedback is very welcome.

13
Jul

The Market

The short video bellow has beautiful images and is also a great metaphor for life. It shows a market in Bangkok that existed for decades but now has a railroad track crossing it (see more details here). And the market adapted to the train. It is a surprising and incredible display of adaptability to the environment.

12
May

Flying with Tornado on AppEngine

Some time ago I bumped into the posts from Francisco Souza on running appengine with several frameworks (tipfy, django, flask and web2py). My choice of micro framework for appengine is tornado, so when reading those posts I thought that one day I would do a remix with the tornado flavor. And here it is, my tornado remix of Francisco series.

First we need to install the needed libs. Assuming the appengine SDK is already installed, we will need tornado and also WTForms (tipfy and flask already include WTForms, with tornado this lib has to be installed separately).

$mkdir gaeseries-tornado
$wget http://github.com/downloads/facebook/tornado/tornado-1.2.1.tar.gz
$tar zxvf tornado-1.2.1.tar.gz
$mv tornado-1.2.1/tornado gaeseries-tornado/
$wget http://pypi.python.org/packages/source/W/WTForms/WTForms-0.6.2.zip
$unzip WTForms-0.6.2.zip
$mv WTForms-0.6.2/wtforms gaeseries-tornado/

So gaeseries-tornado will be our root project directory and by installing tornado and WTForms in the root they will be available in the python path.

So first thing the app.yaml file, just a minimal setup that sends all urls to main.py since we don't have static files.

application: gaeseries
version: 5
runtime: python
api_version: 1

handlers:
- url: /.*
  script: main.py

A first minimal tornado application is set in main.py. When creating the tornado application we give a mapping of URLs and request handlers. The URLs can have regular expressions that will be sent as parameters to the request handler get or post method. A dictionary of settings is also given for the application creation, in this case we need to give the path for the application to find the templates (the "templates" folder will be under the project root folder).

#main.py
import os
import tornado.web
import tornado.wsgi
import wsgiref.handlers
import handlers

settings = {
    'template_path': os.path.join(os.path.dirname(__file__), 'templates'),
    'debug': os.environ.get('SERVER_SOFTWARE', '').startswith('Development/'),
}

application = tornado.wsgi.WSGIApplication([
  (r'/', handlers.PostListingHandler),
], **settings)

def main():
    wsgiref.handlers.CGIHandler().run(application)

if __name__ == '__main__':
    main()

So next we create models.py to have the application models. This file looks exactly like the example for tipfy or flask since it is pure appengine datastore code.

#models.py
from google.appengine.ext import db

class Post(db.Model):
    title = db.StringProperty(required = True)
    content = db.TextProperty(required = True)
    when = db.DateTimeProperty(auto_now_add = True)
    author = db.UserProperty(required = True)

Having defined the model, and we can create the application request handlers. These are classes that process the HTTP requests into responses and are similar to tipfy handlers or flask views.

#handlers.py
import tornado.web
from models import Post

class PostListingHandler(tornado.web.RequestHandler):
    def get(self):
        posts = Post.all()
        self.render('list_posts.html', posts=posts)

The tornado templates are quite similar to django or jinja2 templates, the concept of blocks, loops and if tags is the same. Like jinja2 (and unlike django) the tornado templates allow arbitrary python code. The example base.html follows bellow.

<html>
    <head>
      <meta http-equiv="Content-type" content="text/html; charset=utf-8"/>
      <title>{% block title %}{% end %}</title>
    </head>
    <body>
        {% block content %}
        {% end %}
    </body>
</html>

The list_posts.html template extends the base template.

{% extends "base.html" %}

{% block title %}Posts list{% end %}

{% block content %}
Listing all posts:

<ul>
{% for post in posts %}
	<li>{{ post.title }} (written by {{ post.author.nickname() }})<br />
	{{ post.content }}</li>
{% end %}
</ul>
{% end %}

So now everything is ready to run, although no post will be displayed since no content was added to the datastore.

The next step is to create the pages to post content to the site. This area will need authentication and we will use WTForms to simplify the creation and validation of form data. We will keep the form in a new file named forms.py.

#forms.py
import wtforms as forms
from wtforms import validators
from django.utils.datastructures import MultiValueDict

class Form(forms.Form):
    def __init__(self, handler=None, obj=None, prefix='', formdata=None, **kwargs):
        if handler:
            formdata = MultiValueDict()
            for name in handler.request.arguments.keys():
                formdata.setlist(name, handler.get_arguments(name))            
        forms.Form.__init__(self, formdata, obj=obj, prefix=prefix, **kwargs)

class PostForm(Form):
    title = forms.TextField('Title', validators=[validators.Required()])
    content = forms.TextAreaField('Content', 
				 		validators=[validators.Required()])

In the forms code we had to introduce an extra class to adapt the tornado request handler to a multidict that WTForms needs. The form itself is the same as in tipfy or flask (both also use WTForms). The template for displaying the form, file new_post.html follows.

{% extends "base.html" %}

{% block title %}New post{% end %}

{% block content %}
<form action="{{ request.uri }}" method="post" accept-charset="utf-8">
<p><label for="title">{{ form.title.label() }}</label>
	{{ form.title() }}

    {% if form.title.errors %}
    <ul class="errors">
    	{% for error in form.title.errors %}
        <li>{{ error }}</li>
        {% end %}
    </ul>
    {% end %}
</p>
<p><label for="content">{{ form.content.label() }}</label>
	{{ form.content() }}

    {% if form.content.errors %}
    <ul class="errors">
    	{% for error in form.content.errors %}
        <li>{{ error }}</li>
        {% end %}
    </ul>
    {% end %}
</p>
<p><input type="submit" value="Save post"/></p>
</form>
{% end %}

So finally the use of the form in the request handler. This request handler needs to be protected with only access for administrators. In Tornado one has to subclass the RequestHandler and override the get_current_user method to return the logged user. In this example we use the users appengine api for authentication. The revised handlers.py file has a base class that does authentication and has NewPostHandler that manages the creation of post entries.

#handlers.py
import tornado.web
from google.appengine.api import users
from models import Post
import forms

class BaseHandler(tornado.web.RequestHandler):
    def get_current_user(self):
        user = users.get_current_user()
        if user: 
            user.is_admin = users.is_current_user_admin()
        return user

class PostListingHandler(tornado.web.RequestHandler):
    def get(self):
        posts = Post.all()
        self.render('list_posts.html', posts=posts)

class NewPostHandler(BaseHandler):
    def get(self):
        if not (self.current_user and self.current_user.is_admin):
            return self.redirect(users.create_login_url(self.request.uri))
        form = forms.PostForm()
        self.render('new_post.html', form=form)
    
    def post(self):
        if not (self.current_user and self.current_user.is_admin):
            return self.redirect(users.create_login_url(self.request.uri))
        form = forms.PostForm(self)
        if form.validate():
            post = Post(title=form.title.data,
                        content=form.content.data,
                        author=self.current_user)
            post.put()
            return self.redirect('/')
        self.render('new_posts.html', form=form)

Last piece, modify main.py to add the /new url to the application.

application = tornado.wsgi.WSGIApplication([
  (r'/', handlers.PostListingHandler),
  (r'/new', handlers.NewPostHandler),
], **settings)

So now start the dev_server, go to /new to create some posts. Hope this simple example was enough to give a taste of how simple it is to run a tornado application on appengine.

$python2.5 /usr/local/google_appengine/dev_appserver.py .

This example code is available in this repository.

23
Mar

Blog running on AppEngine using Tornado

This blog is running on appengine for a long time. From the logs it was moved there in April 17, 2009. Today I changed the internal framework used for the blog and this post is to share the performance changes I could measure.

My personal experience with appengine (the cloud computing solution from Google) is quite good for tiny projects like this blog or letras gordas. It is not the cloud scalability that makes me happy, it is more the fact that I can just upload it to the cloud and expect it to continue running without having to do sysadmin work or without having to worry if things break the next time I need to upgrade or change the server software.

The first version of the appengine blog was done in django using django appengine patch, a great work from Waldemar Kornewald that allows running almost standard django in appengine. The django appengine patch is not supported anymore as development moved to django-nonrel that allows the same with a cleaner approach.

Although it is very convenient to be able to write and reuse django code, this framework is not the best option for appengine. It is a large framework that takes a lot of time to load the first time. That is not a problem for normal django deployment where the server is always loaded in memory but it is bad in appengine for apps with few accesses where everything needs to be loaded for most page views (this is called cold start). In order to have fast cold starts people have been using lightweight frameworks (webapp, tipfy, flask, tornado, and probably others) instead of Django. My personal choice currently is tornado.

So using django appengine patch a cold start (bellow) and a hot start (above) measured from Stella for the blog index:

And the same using tornado:

These results could be replicated several times with ~20% variation. So I could confirm the big penalty for Django cold start (from 800-1000ms in Tornado to 2300-2600ms in Django). Both seem to run quite well when running on memory (~200ms). So now this page should load faster. Yeahh.

22
Mar

Back to the surface

After a long dive into facebook caves and twitter deep waters I'm surfacing again to this blog.

It was an interesting experience, it is true that social networks take out some of the motivation to blog. But after a while, facebook starts to look like a boring walled garden and tweeting 140 chars sometimes feels a bit stupid. So this is the start of a new blogging cycle and it feels good.