[Twisted-web] Nevow: Authenticated site with "remember me" and vhosts

Paul Moore pf_moore at yahoo.co.uk
Sat Oct 30 09:03:00 MDT 2004

I'm trying to use Nevow to build a site which displays the results of
a series of SQL queries. It looks good so far, I have the basic site
structure all sorted out in my mind (it's *very* impressive how quick
that was in Nevow). Before I flesh things out much further, I want to
add some authentication - basically, "guest" users will be able to
see a limited subset of the data.

Adding authentication including a "login" form in the sidebar (a bit
like Roundup does) was again very easy. I basically cribbed from the
existing examples. But there are a few things I's now like to add:

1. Ultimately, I want to proxy the app through Apache, so I was using
   the Virtual Host Monster. Im ny original, unauthenticated,
   application, I added a "vhost" child to the main application
   resource, and that was it. I can no longer do that, as the
   resource is wrapped in a guard.SessionWrapper, which doesn't have
   a putChild method. I'm not clear that I want the vhost child to be
   authenticated anyway - what I *think* I want is for "/" to be
   authenticated, but "/vhost" not to be. Or do I? Any suggestions?
2. I'd like to add a "remember me" checkbox, which if checked sets a
   cookie to remember the user's ID, so that they don't have to log
   in again for (say) 2 weeks. Much like gmail, or Yahoo, do. But I'm
   not too sure how I'd go about this. I'm not even sure where I'd
   *put* auto-login code: the page is too late (the guard has done
   its thing by then) but anything else seems to be too early (ie,
   not per-session, if you see what I mean). I suspect I need to
   subclass the Portal, or something, but I'm not sure...

I've scanned the various examples, both in the distribution and in
the Nevow sandbox, but nothing seems to do what I want. Can anyone
give me some pointers?

<off on a tangent>
This is the sort of area where the lack of documentation really
hurts. Examples are great (and the wealth of Nevow examples is realy
nice) but there's a lack of "general principle" documentation to make
it easy to generalise the example code. My best example of this is
that I can't work out what to return from a render_* method - should
it be a function, or a string, or a stan tree, or what? I suspect
that by the magic of interfaces, the answer is "anything that can be
adapted to an ISomething" (which needs further documentation to say
what standard adapters from string, sequence, whatever to ISomething
exist) - but it's not stated anywhere, which makes writing render_*
methods an exciting exercise in experimentation :-)

At the other end of the scale, the source is really too low-level to
follow for this sort of thing (I have tried).

Is there any documentation effort for Nevow going on anywhere? I'd
happily contribute, although it would more likely be in the form of
questions than answers at the moment :-)
</off on a tangent>

FWIW, I attach my driver script below, in case it clarifies my
authentication question above.

-------------- next part --------------
from twisted.application import internet
from twisted.application import service

from twisted.web import static

from nevow import appserver
from nevow import vhost
from nevow import guard
from nevow import inevow

from twisted.cred import portal
from twisted.cred import checkers
from twisted.cred import credentials

from testapp.web import pages

# Authorisation setup.

# First we need a realm, which provides requestAvatar
# TODO: need NotLoggedIn, LoggedIn and noLogout
class MyRealm:
    """A simple implementor of cred's IRealm.
       For web, this gives us the LoggedIn page.
    __implements__ = portal.IRealm

    def requestAvatar(self, avatarId, mind, *interfaces):
        for iface in interfaces:
            if iface is inevow.IResource:
                # do web stuff
                if avatarId is checkers.ANONYMOUS:
                    resc = pages.BasePage()
                    resc = pages.BasePage(avatarId)
		resc.realm = self
		return (inevow.IResource, resc, resc.logout)

        raise NotImplementedError("Can't support that interface.")

# Now create a portal to our realm
realm = MyRealm()
portal = portal.Portal(realm)

# Create a checker for a static list of test users
myChecker = checkers.InMemoryUsernamePasswordDatabaseDontUse()
myChecker.addUser("fred", "flintstone")

# Register our checker, and an anonymous user checker, with the portal
portal.registerChecker(checkers.AllowAnonymousAccess(), credentials.IAnonymous)

application = service.Application('testapp')

# Instead of the application resource being the base page, it becomes a
# SessionWrapper round the portal we created. The base page is part of the
# realm - see above...

# appResource = pages.BasePage()
appResource = guard.SessionWrapper(portal)

#appResource.putChild('robots.txt', static.File('static/robots.txt'))
# SessionWrapper doesn't have a putChild method...
#vResource = vhost.VHostMonsterResource()
#appResource.putChild('vhost', vResource)

webServer = internet.TCPServer(8080, appserver.NevowSite(appResource)) 

# vim:ft=python:
-------------- next part --------------
The scientific name for an animal that doesn't either run from or
fight its enemies is lunch. -- Michael Friedman

More information about the Twisted-web mailing list