HTTP Authentication with Twisted.Web2

  1. Overview
  2. Cred
  3. Credential Factories
  4. The HTTPAuthResource

Overview

twisted.web2.auth implements Digest and Basic HTTP Authentication as specified by RFC 2617. This document attempts to describe:

Cred

twisted.cred is a pluggable authentication framework which allows application/protocol developers to easily support multiple authentication types regardless of the backend used. This document assumes some familiarity with cred and suggests you read Cred: Pluggable Authentication and the twisted.cred API Reference for further information. However several of the application specific implementations of objects required by cred are listed below.

from zope.interface import Interface, implements
from twisted.cred import portal
from twisted.web2.auth.interfaces import IHTTPUser

class HTTPUser(object):
    """
    A user that authenticated over HTTP Auth.
    """
    implements(IHTTPUser)

    username = None

    def __init__(self, username):
        """
        @param username: The str username sent as part of the HTTP auth
            response.
        """
        self.username = username


class HTTPAuthRealm(object):
    implements(portal.IRealm)

    def requestAvatar(self, avatarId, mind, *interfaces):
        if IHTTPUser in interfaces:
            return IHTTPUser, HTTPUser(avatarId)

        raise NotImplementedError("Only IHTTPUser interface is supported")
Listing 1: Cred Setup - ../examples/auth/credsetup.py

Credential Factories

Credential Factories as defined by ICredentialFactory are the heart of HTTP Authentication. Their functions are two-fold:

  1. They provide the challenges and decode the responses from the client, while maintaining state for stateful authentication schemes such as Digest.
  2. They are used to define and determine which authentication schemes should be used during authentication

The ICredentialFactory interface defines the following:

The HTTPAuthResource

The purpose of HTTPAuthResource is to trap both locateChild and renderHTTP and require authentication before allowing requests to pass on to it's wrappedResource. It does this by returning an UnauthorizedResource if the following conditions are not met:

Usage By Example

from twisted.web2 import channel, resource, http, responsecode, server
from twisted.web2.auth.interfaces import IAuthenticatedRequest, IHTTPUser

class ProtectedResource(resource.Resource):
    """
    A resource that is protected by HTTP Auth
    """
    addSlash = True

    def render(self, req):
        """
        I adapt C{req} to an L{IAuthenticatedRequest} before using the
        avatar to return a personalized message.
        """
        avatar = IAuthenticatedRequest(req).avatar

        return http.Response(
            responsecode.OK,
            stream=("Hello %s, you've successfully accessed "
                    "a protected resource." % (avatar.username,)))

from twisted.web2.auth import digest, basic, wrapper

from twisted.cred.portal import Portal
from twisted.cred import checkers

import credsetup

#
# Create the portal with our realm that knows about the kind of avatar
# we want.
#

portal = Portal(credsetup.HTTPAuthRealm())

#
# Create a checker that knows about the type of backend we want to use
# and that knows about the ICredentials we get back from our
# ICredentialFactories.  And tell our portal to use it.
#

checker = checkers.InMemoryUsernamePasswordDatabaseDontUse(guest='guest123')

portal.registerChecker(checker)

#
# Set up our HTTPAuthResource, we have to tell it the root of the resource
# heirarchy we want to protect, as well as the credential factories we want
# to support, the portal we want to use for logging in, and the interfaces
# that IAuthenticatedRequest.avatar to may implement.
#

root = wrapper.HTTPAuthResource(ProtectedResource(),
                                (basic.BasicCredentialFactory('My Realm'),
                                 digest.DigestCredentialFactory('md5',
                                                               'My Realm')),
                                portal, (IHTTPUser,))

site = server.Site(root)

# Start up the server
from twisted.application import service, strports
application = service.Application("HTTP Auth Demo")
s = strports.service('tcp:8080', channel.HTTPFactory(site))
s.setServiceParent(application)
Listing 2: Working HTTPAuthResource Example - ../examples/auth/httpauth.tac

This simple example consists of the following application specific components.

  1. A Resource we wish to protect from unauthorized access, in this case it is our ProtectedResource
  2. A portal using our realm from Listing 1, and having a single ICredentialCheckers. In this case a simple checker that stores usernames and passwords in memory and should not be used for anything other than as an example.
  3. A single ICredentialFactory, in this case a DigestCredentialFactory using the md5 algorithm and with a realm of "My Realm"
  4. A sequence of avatar interfaces consisting of our IHTTPUser as defined in Listing 1

Things HTTPAuthResource doesn't do

HTTPAuthResource is provided largely as a lowest common denominator authentication solution. As a result, it has a few limitations:

As a result of these limitations HTTPAuthResource is provided more as an example of how you can work with twisted.web2.auth rather than as a definitive solution.

Index

Version: 8.1.0