From 819ab070b498ccdf9a4fc33f98b3a8cbda87da69 Mon Sep 17 00:00:00 2001 From: Andrew Resch Date: Tue, 9 Dec 2008 02:12:37 +0000 Subject: [PATCH] Add support for a basic auth transport and handler in rpcserver --- deluge/core/rpcserver.py | 39 +++++++++++++++++++++++++------------ deluge/ui/client.py | 42 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+), 12 deletions(-) diff --git a/deluge/core/rpcserver.py b/deluge/core/rpcserver.py index a927b7b93..f66cb31a5 100644 --- a/deluge/core/rpcserver.py +++ b/deluge/core/rpcserver.py @@ -25,8 +25,9 @@ import gobject -import deluge.SimpleXMLRPCServer as SimpleXMLRPCServer +from deluge.SimpleXMLRPCServer import SimpleXMLRPCServer from SocketServer import ThreadingMixIn +from base64 import decodestring, encodestring from deluge.log import LOG as log import deluge.component as component @@ -36,7 +37,7 @@ def export(func): func._rpcserver_export = True return func -class RPCServer(ThreadingMixIn, SimpleXMLRPCServer.SimpleXMLRPCServer, component.Component): +class RPCServer(component.Component): def __init__(self, port): component.Component.__init__(self, "RPCServer") @@ -53,24 +54,27 @@ class RPCServer(ThreadingMixIn, SimpleXMLRPCServer.SimpleXMLRPCServer, component # Setup the xmlrpc server try: - log.info("Starting XMLRPC server on port %s", port) - SimpleXMLRPCServer.SimpleXMLRPCServer.__init__( - self, (hostname, port), logRequests=False, allow_none=True) - except: + log.info("Starting XMLRPC server %s:%s", hostname, port) + self.server = XMLRPCServer((hostname, port), + requestHandler=BasicAuthXMLRPCRequestHandler, + logRequests=False, + allow_none=True) + except Exception, e: log.info("Daemon already running or port not available..") + log.error(e) sys.exit(0) - self.register_multicall_functions() - self.register_introspection_functions() + self.server.register_multicall_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): """This gets called when there is activity on the socket, ie, data to read or to write.""" - self.handle_request() + self.server.handle_request() return True def register_object(self, obj, name=None): @@ -82,8 +86,9 @@ class RPCServer(ThreadingMixIn, SimpleXMLRPCServer.SimpleXMLRPCServer, component continue if getattr(getattr(obj, d), '_rpcserver_export', False): 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): """Get the request and client address from the socket. 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() self.client_address = client_address[0] 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) diff --git a/deluge/ui/client.py b/deluge/ui/client.py index 6ea617881..df8e594ef 100644 --- a/deluge/ui/client.py +++ b/deluge/ui/client.py @@ -27,6 +27,7 @@ import os.path import socket import struct +import httplib import gobject @@ -37,6 +38,47 @@ import deluge.error from deluge.log import LOG as log 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): # create a HTTP connection object from a host descriptor import httplib