[Twisted-web] civil guards

Andy Gayton andy at thecablelounge.com
Sun Jun 27 21:03:49 MDT 2004


I'm looking for a convenient way to show login error messages.  I've 
made an attempt in the attached civilguard.tac which is a modified 
version of examples/guarded.tac.

It abuses that checkers.ANONYMOUS is really an empty tuple, and instead 
of returning failure.Failure(error.UnauthorizedLogin()) returns a tuple 
with the appropiate error message.

The realm then stretches its definition of ANONYMOUS to be any tuple, 
and hands the NotLoggedIn page this tuple so it gets a chance to render 
the error messages.

It seems like a pretty round about way of doing things though.

Just hoping to get feedback on how others are doing this sort of thing.

cheers!

Andy.
-------------- next part --------------
from twisted.internet import defer
from twisted.application import service, internet
from twisted.cred import portal, checkers, credentials
from nevow import inevow, rend, tags, appserver, guard, loaders


### Renderers

class NotLoggedIn(rend.Page):

    def __init__( self, errors=() ):
        rend.Page.__init__( self )
        self.errors = errors

    def render_errors( self, ctx, data ):
        if self.errors:
            return [
                "Login Error:",
                tags.br(),
                [ tags.strong[error] for error in self.errors ]
            ]
        return ""


    docFactory = loaders.stan(
    tags.html[
        tags.head[tags.title["Not Logged In"]],
        tags.body[
            render_errors,
            tags.form(action=guard.LOGIN_AVATAR)[
                tags.table[
                    tags.tr[
                        tags.td[ "Username:" ],
                        tags.td[ tags.input(type='text',name='username') ],
                    ],
                    tags.tr[
                        tags.td[ "Password:" ],
                        tags.td[ tags.input(type='password',name='password') ],
                    ]
                ],
                tags.input(type='submit'),
                tags.p,
            ]
        ]
    ]
)


class LoggedIn(rend.Page):
    """The resource that is returned when you login"""
    docFactory = loaders.stan(
    tags.html[
        tags.head[tags.title["Logged In"]],
        tags.body[
            tags.h3(render=tags.directive("welcome")),
            tags.a(href=guard.LOGOUT_AVATAR)["Logout"]
        ]
    ]
)

    def render_welcome(self, context, data):
        return context.tag[ "Hello, %s!" % data]

    def logout(self):
        ## self.original is the page's main data -- the object that was passed in to the constructor, and
        ## the object that is initially passed as the 'data' parameter to renderers
        print "%s logged out!" % self.original


### Users

class User:
    def __init__( self, name, password ):
        self.name      = name
        self.password  = password


userdb = {
    "fred" : User( "fred", "fred" ),
    "ned" :  User( "ned",  "ned" ),
}


### Authentication

class SimpleChecker:
    __implements__ = checkers.ICredentialsChecker
    credentialInterfaces = (credentials.IUsernamePassword,)

    def __init__(self, userdb):
        self.userdb = userdb

    def requestAvatarId(self, credentials):
        user = self.userdb.get( credentials.username, None )
        if user is not None:
            return defer.maybeDeferred(
                credentials.checkPassword, user.password).addCallback(
                self._cbPasswordMatch, credentials.username)
        else:
            return ( "No user named: %s" % credentials.username, )


    def _cbPasswordMatch(self, matched, username):
        if matched: return username
        return ( "password didn't match: %s" % username, )


class SimpleRealm:
    __implements__ = portal.IRealm,

    def requestAvatar(self, avatarId, mind, *interfaces):
        for iface in interfaces:
            if iface is inevow.IResource:
                if type(avatarId) is type(checkers.ANONYMOUS):
                    resc = NotLoggedIn( avatarId )
                    resc.realm = self
                    return ( inevow.IResource, resc, lambda : None )
                else:
                    resc = LoggedIn( avatarId )
                    resc.realm = self
                    return ( inevow.IResource, resc, resc.logout )

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



### Application setup

realm = SimpleRealm()
portal = portal.Portal(realm)
myChecker = SimpleChecker( userdb )

portal.registerChecker(checkers.AllowAnonymousAccess(), credentials.IAnonymous)
portal.registerChecker(myChecker)

site = appserver.NevowSite(
    resource=guard.SessionWrapper(portal)
)

application = service.Application("guarded")
internet.TCPServer(8080, site).setServiceParent(application)


More information about the Twisted-web mailing list