Mercurial > p > roundup > code
view roundup/xmlrpc.py @ 3916:57ad3e2c2545
handle bad cookies
Roundup's cgi gets all cookies from all apps on the same server. some
apps aren't as well behaved as roundup and generate cookies that do
not follow the spec perfectly. This causes python's Cookie module to
throw an exception when trying to parse them. In the spirit of being
liberal in what we accept, we create a LiberalCookie class that can
handle those out-of-spec cookies and allow roundup to continue onward.
[SF#1691708]
code from S. Woodside
| author | Justus Pendleton <jpend@users.sourceforge.net> |
|---|---|
| date | Sat, 22 Sep 2007 21:20:57 +0000 |
| parents | c31da624ae3b |
| children | 3c3077582c16 |
line wrap: on
line source
# # Copyright (C) 2007 Stefan Seefeld # All rights reserved. # For license terms see the file COPYING.txt. # import base64 import roundup.instance from roundup import hyperdb from roundup.cgi.exceptions import * from roundup.admin import UsageError from SimpleXMLRPCServer import SimpleXMLRPCRequestHandler class RoundupRequestHandler(SimpleXMLRPCRequestHandler): """A SimpleXMLRPCRequestHandler with support for basic HTTP Authentication.""" def do_POST(self): """Extract username and password from authorization header.""" # Try to extract username and password from HTTP Authentication. self.username = None self.password = None authorization = self.headers.get('authorization', ' ') scheme, challenge = authorization.split(' ', 1) if scheme.lower() == 'basic': decoded = base64.decodestring(challenge) self.username, self.password = decoded.split(':') SimpleXMLRPCRequestHandler.do_POST(self) def _dispatch(self, method, params): """Inject username and password into function arguments.""" # Add username and password to function arguments params = [self.username, self.password] + list(params) return self.server._dispatch(method, params) class RoundupRequest: """Little helper class to handle common per-request tasks such as authentication and login.""" def __init__(self, tracker, username, password): """Open the database for the given tracker, using the given username and password.""" self.tracker = tracker self.db = self.tracker.open('admin') try: userid = self.db.user.lookup(username) except KeyError: # No such user self.db.close() raise Unauthorised, 'Invalid user.' stored = self.db.user.get(userid, 'password') if stored != password: # Wrong password self.db.close() raise Unauthorised, 'Invalid user.' self.db.setCurrentUser(username) def close(self): """Close the database, after committing any changes, if needed.""" if getattr(self, 'db'): try: if self.db.transactions: self.db.commit() finally: self.db.close() def get_class(self, classname): """Return the class for the given classname.""" try: return self.db.getclass(classname) except KeyError: raise UsageError, 'no such class "%s"'%classname def props_from_args(self, cl, args): """Construct a list of properties from the given arguments, and return them after validation.""" props = {} for arg in args: if arg.find('=') == -1: raise UsageError, 'argument "%s" not propname=value'%arg l = arg.split('=') if len(l) < 2: raise UsageError, 'argument "%s" not propname=value'%arg key, value = l[0], '='.join(l[1:]) if value: try: props[key] = hyperdb.rawToHyperdb(self.db, cl, None, key, value) except hyperdb.HyperdbValueError, message: raise UsageError, message else: props[key] = None return props #The server object class RoundupServer: """The RoundupServer provides the interface accessible through the Python XMLRPC mapping. All methods take an additional username and password argument so each request can be authenticated.""" def __init__(self, tracker, verbose = False): self.tracker = roundup.instance.open(tracker) self.verbose = verbose def list(self, username, password, classname, propname = None): r = RoundupRequest(self.tracker, username, password) cl = r.get_class(classname) if not propname: propname = cl.labelprop() result = [cl.get(id, propname) for id in cl.list()] r.close() return result def display(self, username, password, designator, *properties): r = RoundupRequest(self.tracker, username, password) classname, nodeid = hyperdb.splitDesignator(designator) cl = r.get_class(classname) props = properties and list(properties) or cl.properties.keys() props.sort() result = [(property, cl.get(nodeid, property)) for property in props] r.close() return dict(result) def create(self, username, password, classname, *args): r = RoundupRequest(self.tracker, username, password) cl = r.get_class(classname) # convert types props = r.props_from_args(cl, args) # check for the key property key = cl.getkey() if key and not props.has_key(key): raise UsageError, 'you must provide the "%s" property.'%key # do the actual create try: try: result = cl.create(**props) except (TypeError, IndexError, ValueError), message: raise UsageError, message finally: r.close() return result def set(self, username, password, designator, *args): r = RoundupRequest(self.tracker, username, password) classname, itemid = hyperdb.splitDesignator(designator) cl = r.get_class(classname) # convert types props = r.props_from_args(cl, args) try: try: cl.set(itemid, **props) except (TypeError, IndexError, ValueError), message: raise UsageError, message finally: r.close() # vim: set et sts=4 sw=4 :
