Posts Tagged ‘cookies’

Python XML-RPC Client with Cookie Handling and SSL

Sunday, March 9th, 2008

The following is an adaptation of Vaibhav Bhatia’s cookie-handling XML-RPC client (text source) with a few changes to implement SSL for HTTPS transport in place of the basic HTTP transport.

This was done specifically for use with CherryPy sessions so that the XML-RPC client (the server proxy object) could be stored in a session variable, giving each user an individual client and thus allowing webservice permissions to be handled on a per-user basis (without having to authenticate and determine permissions on every webservice method invocation). To do this, make sure that you’re storing CherryPy sessions in memory, not in a file, and then create the proxy object (sorry for the gigantic class name):

cherrypy.session['proxy'] = \
xmlrpclib.ServerProxy(url, transport=CookieAuthXMLRPCSafeTransport())

xmlrpcclient.py

import os
import base64
import xmlrpclib
import urllib2
import cookielib
 
class CookieAuthXMLRPCSafeTransport(xmlrpclib.SafeTransport):
""" xmlrpclib.Transport that sends HTTPS Authentication"""
 
user_agent = '*py*'
credentials = ()
cookiefile = 'cookies.lwp'
 
def send_basic_auth(self, connection):
"""Include HTTPS Authentication data in a header"""
 
auth = base64.encodestring("%s:%s"%self.credentials).strip()
auth = 'Basic %s' %(auth,)
connection.putheader('Authorization',auth)
 
def send_cookie_auth(self, connection):
"""Include Cookie Authentication data in a header"""
 
cj = cookielib.LWPCookieJar()
cj.load(self.cookiefile)
 
for cookie in cj:
if cookie.name == 'session_id':
uuidstr = cookie.value
connection.putheader("Cookie",cookie.name+'='+cookie.value)
 
## override the send_host hook to also send authentication info
def send_host(self, connection, host):
xmlrpclib.SafeTransport.send_host(self, connection, host)
if os.path.exists(self.cookiefile):
self.send_cookie_auth(connection)
elif self.credentials != ():
self.send_basic_auth(connection)
 
def request(self, host, handler, request_body, verbose=0):
# dummy request class for extracting cookies
class CookieRequest(urllib2.Request):
pass
 
# dummy response class for extracting cookies
class CookieResponse:
def __init__(self, headers):
self.headers = headers
def info(self):
return self.headers
 
crequest = CookieRequest('https://'+host+'/')
 
# issue XML-RPC request
h = self.make_connection(host)
if verbose:
h.set_debuglevel(1)
 
self.send_request(h, handler, request_body)
self.send_host(h, host)
self.send_user_agent(h)
 
# creating a cookie jar for my cookies
cj = cookielib.LWPCookieJar()
 
self.send_content(h, request_body)
 
errcode, errmsg, headers = h.getreply()
 
cresponse = CookieResponse(headers)
cj.extract_cookies(cresponse, crequest)
 
if len(cj) > 0 and self.cookiefile != None:
cj.save(self.cookiefile)
 
if errcode != 200:
raise xmlrpclib.ProtocolError(
host + handler,
errcode, errmsg,
headers
)
 
self.verbose = verbose
 
return self.parse_response(h.getfile())