""" A demo app that can protect arbitrarily deep hierarchies. Try e.g. http://localhost:8081/secret/stuff/stuff/stuff/ without authenticating first. Requirements: - Main page and some subpages do not need authentication. - There are multiple subpages that require authentication. - Pages that require authentication must show a login dialog, and after a succesful login act as if user was logged in already. - The subpages requiring authentication may be deeply linked into from each other or the non-authenticating pages. - The authentication should be shared amongst all the pages. """ from twisted.web.woven import simpleguard, page, guard from twisted.web import resource, util, microdom from twisted.cred import checkers, portal from twisted.python import urlpath class LoginPage(page.Page): isLeaf = True """This is the page that is shown to non-logged in users.""" addSlash = 0 template = ''' Login

Please Log In

''' def __init__(self, formModel=None): page.Page.__init__(self) self.formModel = formModel def wvupdate_loginform(self, request, widget, model): root = request.getRootURL() if root is None: root=request.prePathURL() url = urlpath.URLPath.fromString(root) microdom.lmx(widget.node).form( action=str(url.sibling(guard.INIT_PERSPECTIVE)), model="form") def wmfactory_form(self, request): if self.formModel: return self.formModel else: return guard.newLoginSignature.method(None) class Authenticated(page.Page): template='''Hello ! Look at all the stuff, or go up''' def wmfactory_name(self, request): return request.getComponent(simpleguard.Authenticated).name def wchild_stuff(self, request): return self class Another(page.Page): template="""This is another page requiring authentication. And there's more. Go up.""" def wchild_more(self, request): return self from twisted.python import components class IRedirectAfterLogin(components.Interface): """The URLPath to which we will redirect after successful login. """ class Here(resource.Resource): def render(self, request): existing = request.getSession().getComponent(IRedirectAfterLogin, None) if existing is not None: request.redirect(str(existing)) request.getSession().setComponent(IRedirectAfterLogin, None) return "" else: return util.redirectTo('.', request) def callback(model): return Here() class FullURLRequest: def __init__(self, request): self.request = request def prePathURL(self): r = self.request prepath = r.prepath r.prepath = r.prepath + r.postpath rv = r.prePathURL() r.prepath = prepath return rv class InfiniChild(resource.Resource): def __init__(self, r): resource.Resource.__init__(self) self.r = r def getChild(self, name, request): return self def render(self, request): request.getSession().setComponent( IRedirectAfterLogin, urlpath.URLPath.fromRequest(FullURLRequest(request)) ) return self.r.render(request) class MainPage(page.Page): appRoot = True template='''\ Main page secret, deep secret, another, another deep, up. ''' def wchild_secret(self, request): a=request.getComponent(simpleguard.Authenticated) if not request.getComponent(simpleguard.Authenticated): return InfiniChild(LoginPage()) return Authenticated() def wchild_another(self, request): a=request.getComponent(simpleguard.Authenticated) if not request.getComponent(simpleguard.Authenticated): return InfiniChild(LoginPage()) return Another() def createResource(): return simpleguard.guardResource( MainPage(), [checkers.InMemoryUsernamePasswordDatabaseDontUse(test="test")], callback=callback)