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.
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()
else:
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("user","password")
myChecker.addUser("fred", "flintstone")
# Register our checker, and an anonymous user checker, with the portal
portal.registerChecker(checkers.AllowAnonymousAccess(), credentials.IAnonymous)
portal.registerChecker(myChecker)
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))
webServer.setServiceParent(application)
# vim:ft=python:
Paul
--
The scientific name for an animal that doesn't either run from or
fight its enemies is lunch. -- Michael Friedman