Add support for a basic auth transport and handler in rpcserver

This commit is contained in:
Andrew Resch 2008-12-09 02:12:37 +00:00
commit 819ab070b4
2 changed files with 69 additions and 12 deletions

View file

@ -25,8 +25,9 @@
import gobject import gobject
import deluge.SimpleXMLRPCServer as SimpleXMLRPCServer from deluge.SimpleXMLRPCServer import SimpleXMLRPCServer
from SocketServer import ThreadingMixIn from SocketServer import ThreadingMixIn
from base64 import decodestring, encodestring
from deluge.log import LOG as log from deluge.log import LOG as log
import deluge.component as component import deluge.component as component
@ -36,7 +37,7 @@ def export(func):
func._rpcserver_export = True func._rpcserver_export = True
return func return func
class RPCServer(ThreadingMixIn, SimpleXMLRPCServer.SimpleXMLRPCServer, component.Component): class RPCServer(component.Component):
def __init__(self, port): def __init__(self, port):
component.Component.__init__(self, "RPCServer") component.Component.__init__(self, "RPCServer")
@ -53,24 +54,27 @@ class RPCServer(ThreadingMixIn, SimpleXMLRPCServer.SimpleXMLRPCServer, component
# Setup the xmlrpc server # Setup the xmlrpc server
try: try:
log.info("Starting XMLRPC server on port %s", port) log.info("Starting XMLRPC server %s:%s", hostname, port)
SimpleXMLRPCServer.SimpleXMLRPCServer.__init__( self.server = XMLRPCServer((hostname, port),
self, (hostname, port), logRequests=False, allow_none=True) requestHandler=BasicAuthXMLRPCRequestHandler,
except: logRequests=False,
allow_none=True)
except Exception, e:
log.info("Daemon already running or port not available..") log.info("Daemon already running or port not available..")
log.error(e)
sys.exit(0) sys.exit(0)
self.register_multicall_functions() self.server.register_multicall_functions()
self.register_introspection_functions() self.server.register_introspection_functions()
self.socket.setblocking(False) self.server.socket.setblocking(False)
gobject.io_add_watch(self.socket.fileno(), gobject.IO_IN | gobject.IO_OUT | gobject.IO_PRI | gobject.IO_ERR | gobject.IO_HUP, self._on_socket_activity) gobject.io_add_watch(self.server.socket.fileno(), gobject.IO_IN | gobject.IO_OUT | gobject.IO_PRI | gobject.IO_ERR | gobject.IO_HUP, self._on_socket_activity)
def _on_socket_activity(self, source, condition): def _on_socket_activity(self, source, condition):
"""This gets called when there is activity on the socket, ie, data to read """This gets called when there is activity on the socket, ie, data to read
or to write.""" or to write."""
self.handle_request() self.server.handle_request()
return True return True
def register_object(self, obj, name=None): def register_object(self, obj, name=None):
@ -82,8 +86,9 @@ class RPCServer(ThreadingMixIn, SimpleXMLRPCServer.SimpleXMLRPCServer, component
continue continue
if getattr(getattr(obj, d), '_rpcserver_export', False): if getattr(getattr(obj, d), '_rpcserver_export', False):
log.debug("Registering method: %s", name + "." + d) log.debug("Registering method: %s", name + "." + d)
self.register_function(getattr(obj, d), name + "." + d) self.server.register_function(getattr(obj, d), name + "." + d)
class XMLRPCServer(ThreadingMixIn, SimpleXMLRPCServer):
def get_request(self): def get_request(self):
"""Get the request and client address from the socket. """Get the request and client address from the socket.
We override this so that we can get the ip address of the client. We override this so that we can get the ip address of the client.
@ -91,3 +96,13 @@ class RPCServer(ThreadingMixIn, SimpleXMLRPCServer.SimpleXMLRPCServer, component
request, client_address = self.socket.accept() request, client_address = self.socket.accept()
self.client_address = client_address[0] self.client_address = client_address[0]
return (request, client_address) return (request, client_address)
class BasicAuthXMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
def do_POST(self):
auth = self.headers['authorization']
auth = auth.replace("Basic ","")
decoded_auth = decodestring(auth)
# Check authentication here
# if cannot authenticate, end the connection or
# otherwise call original
return SimpleXMLRPCRequestHandler.do_POST(self)

View file

@ -27,6 +27,7 @@
import os.path import os.path
import socket import socket
import struct import struct
import httplib
import gobject import gobject
@ -37,6 +38,47 @@ import deluge.error
from deluge.log import LOG as log from deluge.log import LOG as log
class Transport(xmlrpclib.Transport): class Transport(xmlrpclib.Transport):
def __init__(self, username=None, password=None, use_datetime=0):
self.__username = username
self.__password = password
self._use_datetime = use_datetime
def request(self, host, handler, request_body, verbose=0):
# 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)
if self.__username is not None and self.__password is not None:
h.putheader("AUTHORIZATION", "Basic %s" % string.replace(
encodestring("%s:%s" % (self.__username, self.__password)),
"\012", ""))
self.send_content(h, request_body)
errcode, errmsg, headers = h.getreply()
if errcode != 200:
raise ProtocolError(
host + handler,
errcode, errmsg,
headers
)
self.verbose = verbose
try:
sock = h._conn.sock
except AttributeError:
sock = None
return self._parse_response(h.getfile(), sock)
def make_connection(self, host): def make_connection(self, host):
# create a HTTP connection object from a host descriptor # create a HTTP connection object from a host descriptor
import httplib import httplib