Index: third_party/twisted_8_1/twisted/web/woven/guard.py |
diff --git a/third_party/twisted_8_1/twisted/web/woven/guard.py b/third_party/twisted_8_1/twisted/web/woven/guard.py |
deleted file mode 100644 |
index ab5d56be279c05e5db5d69316690c8825b352a55..0000000000000000000000000000000000000000 |
--- a/third_party/twisted_8_1/twisted/web/woven/guard.py |
+++ /dev/null |
@@ -1,383 +0,0 @@ |
-# -*- test-case-name: twisted.web.test.test_woven -*- |
- |
-# Copyright (c) 2001-2004 Twisted Matrix Laboratories. |
-# See LICENSE for details. |
- |
-# |
- |
-"""Resource protection for Woven. If you wish to use twisted.cred to protect |
-your Woven application, you are probably most interested in |
-L{UsernamePasswordWrapper}. |
-""" |
- |
-from __future__ import nested_scopes |
- |
-__version__ = "$Revision: 1.34 $"[11:-2] |
- |
-import random |
-import time |
-import md5 |
-import urllib |
- |
-# Twisted Imports |
- |
-from twisted.python import log, components |
-from twisted.web.resource import Resource, IResource |
-from twisted.web.util import redirectTo, Redirect, DeferredResource |
-from twisted.web.static import addSlash |
-from twisted.internet import reactor |
-from twisted.cred.error import LoginFailed, UnauthorizedLogin |
- |
-def _sessionCookie(): |
- return md5.new("%s_%s" % (str(random.random()) , str(time.time()))).hexdigest() |
- |
-class GuardSession(components.Componentized): |
- """A user's session with a system. |
- |
- This utility class contains no functionality, but is used to |
- represent a session. |
- """ |
- def __init__(self, guard, uid): |
- """Initialize a session with a unique ID for that session. |
- """ |
- components.Componentized.__init__(self) |
- self.guard = guard |
- self.uid = uid |
- self.expireCallbacks = [] |
- self.checkExpiredID = None |
- self.setLifetime(60) |
- self.services = {} |
- self.portals = {} |
- self.touch() |
- |
- def _getSelf(self, interface=None): |
- self.touch() |
- if interface is None: |
- return self |
- else: |
- return self.getComponent(interface) |
- |
- # Old Guard interfaces |
- |
- def clientForService(self, service): |
- x = self.services.get(service) |
- if x: |
- return x[1] |
- else: |
- return x |
- |
- def setClientForService(self, ident, perspective, client, service): |
- if self.services.has_key(service): |
- p, c, i = self.services[service] |
- p.detached(c, ident) |
- del self.services[service] |
- else: |
- self.services[service] = perspective, client, ident |
- perspective.attached(client, ident) |
- # this return value is useful for services that need to do asynchronous |
- # stuff. |
- return client |
- |
- # New Guard Interfaces |
- |
- def resourceForPortal(self, port): |
- return self.portals.get(port) |
- |
- def setResourceForPortal(self, rsrc, port, logout): |
- self.portalLogout(port) |
- self.portals[port] = rsrc, logout |
- return rsrc |
- |
- def portalLogout(self, port): |
- p = self.portals.get(port) |
- if p: |
- r, l = p |
- try: l() |
- except: log.err() |
- del self.portals[port] |
- |
- # timeouts and expiration |
- |
- def setLifetime(self, lifetime): |
- """Set the approximate lifetime of this session, in seconds. |
- |
- This is highly imprecise, but it allows you to set some general |
- parameters about when this session will expire. A callback will be |
- scheduled each 'lifetime' seconds, and if I have not been 'touch()'ed |
- in half a lifetime, I will be immediately expired. |
- """ |
- self.lifetime = lifetime |
- |
- def notifyOnExpire(self, callback): |
- """Call this callback when the session expires or logs out. |
- """ |
- self.expireCallbacks.append(callback) |
- |
- def expire(self): |
- """Expire/logout of the session. |
- """ |
- log.msg("expired session %s" % self.uid) |
- del self.guard.sessions[self.uid] |
- for c in self.expireCallbacks: |
- try: |
- c() |
- except: |
- log.err() |
- self.expireCallbacks = [] |
- if self.checkExpiredID: |
- self.checkExpiredID.cancel() |
- self.checkExpiredID = None |
- |
- def touch(self): |
- self.lastModified = time.time() |
- |
- def checkExpired(self): |
- self.checkExpiredID = None |
- # If I haven't been touched in 15 minutes: |
- if time.time() - self.lastModified > self.lifetime / 2: |
- if self.guard.sessions.has_key(self.uid): |
- self.expire() |
- else: |
- log.msg("no session to expire: %s" % self.uid) |
- else: |
- log.msg("session given the will to live for %s more seconds" % self.lifetime) |
- self.checkExpiredID = reactor.callLater(self.lifetime, |
- self.checkExpired) |
- def __getstate__(self): |
- d = self.__dict__.copy() |
- if d.has_key('checkExpiredID'): |
- del d['checkExpiredID'] |
- return d |
- |
- def __setstate__(self, d): |
- self.__dict__.update(d) |
- self.touch() |
- self.checkExpired() |
- |
-INIT_SESSION = 'session-init' |
- |
-def _setSession(wrap, req, cook): |
- req.session = wrap.sessions[cook] |
- req.getSession = req.session._getSelf |
- |
-def urlToChild(request, *ar, **kw): |
- pp = request.prepath.pop() |
- orig = request.prePathURL() |
- request.prepath.append(pp) |
- c = '/'.join(ar) |
- if orig[-1] == '/': |
- # this SHOULD only happen in the case where the URL is just the hostname |
- ret = orig + c |
- else: |
- ret = orig + '/' + c |
- args = request.args.copy() |
- args.update(kw) |
- if args: |
- ret += '?'+urllib.urlencode(args) |
- return ret |
- |
-def redirectToSession(request, garbage): |
- rd = Redirect(urlToChild(request, *request.postpath, **{garbage:1})) |
- rd.isLeaf = 1 |
- return rd |
- |
-SESSION_KEY='__session_key__' |
- |
-class SessionWrapper(Resource): |
- |
- sessionLifetime = 1800 |
- |
- def __init__(self, rsrc, cookieKey=None): |
- Resource.__init__(self) |
- self.resource = rsrc |
- if cookieKey is None: |
- cookieKey = "woven_session_" + _sessionCookie() |
- self.cookieKey = cookieKey |
- self.sessions = {} |
- |
- def render(self, request): |
- return redirectTo(addSlash(request), request) |
- |
- def getChild(self, path, request): |
- if not request.prepath: |
- return None |
- cookie = request.getCookie(self.cookieKey) |
- setupURL = urlToChild(request, INIT_SESSION, *([path]+request.postpath)) |
- request.setupSessionURL = setupURL |
- request.setupSession = lambda: Redirect(setupURL) |
- if path.startswith(SESSION_KEY): |
- key = path[len(SESSION_KEY):] |
- if key not in self.sessions: |
- return redirectToSession(request, '__start_session__') |
- self.sessions[key].setLifetime(self.sessionLifetime) |
- if cookie == key: |
- # /sessionized-url/${SESSION_KEY}aef9c34aecc3d9148/foo |
- # ^ |
- # we are this getChild |
- # with a matching cookie |
- return redirectToSession(request, '__session_just_started__') |
- else: |
- # We attempted to negotiate the session but failed (the user |
- # probably has cookies disabled): now we're going to return the |
- # resource we contain. In general the getChild shouldn't stop |
- # there. |
- # /sessionized-url/${SESSION_KEY}aef9c34aecc3d9148/foo |
- # ^ we are this getChild |
- # without a cookie (or with a mismatched cookie) |
- _setSession(self, request, key) |
- return self.resource |
- elif cookie in self.sessions: |
- # /sessionized-url/foo |
- # ^ we are this getChild |
- # with a session |
- _setSession(self, request, cookie) |
- return getResource(self.resource, path, request) |
- elif path == INIT_SESSION: |
- # initialize the session |
- # /sessionized-url/session-init |
- # ^ this getChild |
- # without a session |
- newCookie = _sessionCookie() |
- request.addCookie(self.cookieKey, newCookie, path="/") |
- sz = self.sessions[newCookie] = GuardSession(self, newCookie) |
- sz.checkExpired() |
- rd = Redirect(urlToChild(request, SESSION_KEY+newCookie, |
- *request.postpath)) |
- rd.isLeaf = 1 |
- return rd |
- else: |
- # /sessionized-url/foo |
- # ^ we are this getChild |
- # without a session |
- request.getSession = lambda interface=None: None |
- return getResource(self.resource, path, request) |
- |
-def getResource(resource, path, request): |
- if resource.isLeaf: |
- request.postpath.insert(0, request.prepath.pop()) |
- return resource |
- else: |
- return resource.getChildWithDefault(path, request) |
- |
-INIT_PERSPECTIVE = 'perspective-init' |
-DESTROY_PERSPECTIVE = 'perspective-destroy' |
- |
-from twisted.python import formmethod as fm |
-from twisted.web.woven import form |
- |
- |
-newLoginSignature = fm.MethodSignature( |
- fm.String("username", "", |
- "Username", "Your user name."), |
- fm.Password("password", "", |
- "Password", "Your password."), |
- fm.Submit("submit", choices=[("Login", "", "")], allowNone=1), |
- ) |
- |
-from twisted.cred.credentials import UsernamePassword, Anonymous |
- |
-class UsernamePasswordWrapper(Resource): |
- """I bring a C{twisted.cred} Portal to the web. Use me to provide different Resources |
- (usually entire pages) based on a user's authentication details. |
- |
- A C{UsernamePasswordWrapper} is a |
- L{Resource<twisted.web.resource.Resource>}, and is usually wrapped in a |
- L{SessionWrapper} before being inserted into the site tree. |
- |
- The L{Realm<twisted.cred.portal.IRealm>} associated with your |
- L{Portal<twisted.cred.portal.Portal>} should be prepared to accept a |
- request for an avatar that implements the L{twisted.web.resource.IResource} |
- interface. This avatar should probably be something like a Woven |
- L{Page<twisted.web.woven.page.Page>}. That is, it should represent a whole |
- web page. Once you return this avatar, requests for it's children do not go |
- through guard. |
- |
- If you want to determine what unauthenticated users see, make sure your |
- L{Portal<twisted.cred.portal.Portal>} has a checker associated that allows |
- anonymous access. (See L{twisted.cred.checkers.AllowAnonymousAccess}) |
- |
- """ |
- |
- def __init__(self, portal, callback=None, errback=None): |
- """Constructs a UsernamePasswordWrapper around the given portal. |
- |
- @param portal: A cred portal for your web application. The checkers |
- associated with this portal must be able to accept username/password |
- credentials. |
- @type portal: L{twisted.cred.portal.Portal} |
- |
- @param callback: Gets called after a successful login attempt. |
- A resource that redirects to "." will display the avatar resource. |
- If this parameter isn't provided, defaults to a standard Woven |
- "Thank You" page. |
- @type callback: A callable that accepts a Woven |
- L{model<twisted.web.woven.interfaces.IModel>} and returns a |
- L{IResource<twisted.web.resource.Resource>}. |
- |
- @param errback: Gets called after a failed login attempt. |
- If this parameter is not provided, defaults to a the standard Woven |
- form error (i.e. The original form on a page of its own, with |
- errors noted.) |
- @type errback: A callable that accepts a Woven |
- L{model<twisted.web.woven.interfaces.IModel>} and returns a |
- L{IResource<twisted.web.resource.Resource>}. |
- """ |
- Resource.__init__(self) |
- self.portal = portal |
- self.callback = callback |
- self.errback = errback |
- |
- def _ebFilter(self, f): |
- f.trap(LoginFailed, UnauthorizedLogin) |
- raise fm.FormException(password="Login failed, please enter correct username and password.") |
- |
- def getChild(self, path, request): |
- s = request.getSession() |
- if s is None: |
- return request.setupSession() |
- if path == INIT_PERSPECTIVE: |
- def loginSuccess(result): |
- interface, avatarAspect, logout = result |
- s.setResourceForPortal(avatarAspect, self.portal, logout) |
- |
- def triggerLogin(username, password, submit=None): |
- return self.portal.login( |
- UsernamePassword(username, password), |
- None, |
- IResource |
- ).addCallback( |
- loginSuccess |
- ).addErrback( |
- self._ebFilter |
- ) |
- |
- return form.FormProcessor( |
- newLoginSignature.method( |
- triggerLogin |
- ), |
- callback=self.callback, |
- errback=self.errback |
- ) |
- elif path == DESTROY_PERSPECTIVE: |
- s.portalLogout(self.portal) |
- return Redirect(".") |
- else: |
- r = s.resourceForPortal(self.portal) |
- if r: |
- ## Delegate our getChild to the resource our portal says is the right one. |
- return getResource(r[0], path, request) |
- else: |
- return DeferredResource( |
- self.portal.login(Anonymous(), None, IResource |
- ).addCallback( |
- lambda (interface, avatarAspect, logout): |
- getResource(s.setResourceForPortal(avatarAspect, |
- self.portal, logout), |
- path, request))) |
- |
- |
- |
-from twisted.web.woven import interfaces, utils |
-## Dumb hack until we have an ISession and use interface-to-interface adaption |
-components.registerAdapter(utils.WovenLivePage, GuardSession, interfaces.IWovenLivePage) |
- |