## Basic HTTP Authentication with XMLRPC in Python

From: "andrew cooke" <andrew@...>

Date: Wed, 31 Dec 2008 17:42:05 -0300 (CLST)

I couldn't find anywhere on the 'net that clearly documented this - there
are various old discussions, but they tend to be out of date.  So here's a
brief sketch of what works.

[Note that HTTP basic authentication - RFC 2617
http://www.faqs.org/rfcs/rfc2617.html - effectively sends username and
password as cleartext.  This is not secure.  As far as I can tell, digest
authentication is not supported, so a more secure (but more complex)
solution would involve SSL (a possible compromise would be basic auth over
SSL, which would only require a server certificate, but which has its own
limitations).]

On the client side, nothing is needed except that username and password
should be placed in the URL used.  The libraries used by xmlrpclib will
construct the correct HTTP header (see below).  So the client code is
simply:

import xmlrpclib
server = xmlrpclib.ServerProxy('http://user:pass@...')
...

But, obviously, a more typical use case would supply dynamic values.

This generates the Authorization HTTP header, with the format (RFC 2617):

Authorization: Basic Zm9vOmJhcg==

where Zm9vOmJhcg== is the base64 encoding of, in this case, "foo:bar"
retrieved:

from base64 import b64decode
...
(basic, _, encoded) = \
assert basic == 'Basic', 'Only basic authentication supported'

The only remaining part of the puzzle, then, is how to get the headers.
Poking around in the source it seems that it is necessary to override
BaseHTTPServer.BaseHTTPRequestHandler.parse_request (which is subclassed
bySimpleXMLRPCServer.SimpleXMLRPCRequestHandler).

So a suitable server class would look like:

from SimpleXMLRPCServer import SimpleXMLRPCServer, \
SimpleXMLRPCRequestHandler

class VerifyingServer(SimpleXMLRPCServer):

def __init__(self, ..., *args, **kargs):
# we use an inner class so that we can call out to the
# authenticate method
class VerifyingRequestHandler(SimpleXMLRPCRequestHandler):
# this is the method we must override
def parse_request(myself):
# first, call the original implementation which returns
# True if all OK so far
if SimpleXMLRPCRequestHandler.parse_request(myself):
# next we authenticate
return True
else:
# if authentication fails, tell the client
myself.send_error(401, 'Authentication failed')
return False
# and intialise the superclass with the above
SimpleXMLRPCServer.__init__(self,
requestHandler=VerifyingRequestHandler,
*args, **kargs)

Andrew