示例#1
0
    def __init__(self, url_name='root', restrict_introspection=False):
        self.url_name = url_name
        self.rpcmethods = []  # a list of RPCMethod objects
        self.jsonrpcdispatcher = JSONRPCDispatcher()
        self.xmlrpcdispatcher = XMLRPCDispatcher()

        if not restrict_introspection:
            self.register_method(self.system_listmethods)
            self.register_method(self.system_methodhelp)
            self.register_method(self.system_methodsignature)
            self.register_method(self.system_describe)
示例#2
0
    def __init__(self, url='', apps=[], restrict_introspection=False):
        version = platform.python_version_tuple()
        self.url = url
        self.rpcmethods = []  # a list of RPCMethod objects
        self.jsonrpcdispatcher = JSONRPCDispatcher()
        self.xmlrpcdispatcher = XMLRPCDispatcher()

        if not restrict_introspection:
            self.register_method(self.system_listmethods)
            self.register_method(self.system_methodhelp)
            self.register_method(self.system_methodsignature)
            self.register_method(self.system_describe)

        self.register_rpcmethods(apps)
示例#3
0
 def __init__(self, url_name='root', restrict_introspection=False):
     self.url_name = url_name
     self.rpcmethods = []        # a list of RPCMethod objects
     self.jsonrpcdispatcher = JSONRPCDispatcher()
     self.xmlrpcdispatcher = XMLRPCDispatcher()
         
     if not restrict_introspection:
         self.register_method(self.system_listmethods)
         self.register_method(self.system_methodhelp)
         self.register_method(self.system_methodsignature)
         self.register_method(self.system_describe)
示例#4
0
 def __init__(self, url='', apps=[], restrict_introspection=False):
     version = platform.python_version_tuple()
     self.url = url
     self.rpcmethods = []        # a list of RPCMethod objects
     self.jsonrpcdispatcher = JSONRPCDispatcher()
     self.xmlrpcdispatcher = XMLRPCDispatcher()
         
     if not restrict_introspection:
         self.register_method(self.system_listmethods)
         self.register_method(self.system_methodhelp)
         self.register_method(self.system_methodsignature)
         self.register_method(self.system_describe)
         
     self.register_rpcmethods(apps)
示例#5
0
    def __init__(self, url='', apps=[], restrict_introspection=False,
            restrict_ootb_auth=True, json_encoder=None):
        version = platform.python_version_tuple()
        self.url = url
        self.rpcmethods = []        # a list of RPCMethod objects
        self.jsonrpcdispatcher = JSONRPCDispatcher(json_encoder)

        if not restrict_introspection:
            self.register_method(self.system_listmethods)
            self.register_method(self.system_methodhelp)
            self.register_method(self.system_methodsignature)
            self.register_method(self.system_describe)

        if not restrict_ootb_auth:
            self.register_method(self.system_login)
            self.register_method(self.system_logout)

        self.register_rpcmethods(apps)
示例#6
0
    def __init__(self, url="", apps=[], restrict_introspection=False):
        version = platform.python_version_tuple()
        self.url = url
        self.rpcmethods = []  # a list of RPCMethod objects
        self.jsonrpcdispatcher = JSONRPCDispatcher()

        if int(version[0]) < 3 and int(version[1]) < 5:
            # this is for python 2.4 and below
            self.xmlrpcdispatcher = SimpleXMLRPCDispatcher()
        else:
            # python 2.5+ requires different parameters
            self.xmlrpcdispatcher = SimpleXMLRPCDispatcher(allow_none=False, encoding=None)

        if not restrict_introspection:
            self.register_method(self.system_listmethods)
            self.register_method(self.system_methodhelp)
            self.register_method(self.system_methodsignature)
            self.register_method(self.system_describe)

        self.register_rpcmethods(apps)
示例#7
0
class RPCDispatcher:
    '''
    Dispatches method calls to either the xmlrpc or jsonrpc dispatcher
    '''
    
    def __init__(self, url='', apps=[], restrict_introspection=False):
        version = platform.python_version_tuple()
        self.url = url
        self.rpcmethods = []        # a list of RPCMethod objects
        self.jsonrpcdispatcher = JSONRPCDispatcher()
        self.xmlrpcdispatcher = XMLRPCDispatcher()
            
        if not restrict_introspection:
            self.register_method(self.system_listmethods)
            self.register_method(self.system_methodhelp)
            self.register_method(self.system_methodsignature)
            self.register_method(self.system_describe)
            
        self.register_rpcmethods(apps)
        
    @rpcmethod(name='system.describe', signature=['struct'])
    def system_describe(self):
        '''
        Returns a simple method description of the methods supported
        '''
        
        description = {}
        description['serviceType'] = 'RPC4Django JSONRPC+XMLRPC'
        description['serviceURL'] = self.url,
        description['methods'] = [{'name': method.name, 
                                   'summary': method.help, 
                                   'params': method.get_params(),
                                   'return': method.get_returnvalue()} \
                                  for method in self.rpcmethods]
        
        return description
    
    @rpcmethod(name='system.listMethods', signature=['array'])
    def system_listmethods(self):
        '''
        Returns a list of supported methods
        '''
        
        methods = [method.name for method in self.rpcmethods]
        methods.sort()
        return methods
    
    @rpcmethod(name='system.methodHelp', signature=['string', 'string'])
    def system_methodhelp(self, method_name):
        '''
        Returns documentation for a specified method
        '''
        
        for method in self.rpcmethods:
            if method.name == method_name:
                return method.help
            
        # this differs from what implementation in SimpleXMLRPCServer does
        # this will report via a fault or error while SimpleXMLRPCServer
        # just returns an empty string
        raise Fault(APPLICATION_ERROR, 'No method found with name: ' + \
                    str(method_name))
          
    @rpcmethod(name='system.methodSignature', signature=['array', 'string'])
    def system_methodsignature(self, method_name):
        '''
        Returns the signature for a specified method 
        '''
        
        for method in self.rpcmethods:
            if method.name == method_name:
                return method.signature
        raise Fault(APPLICATION_ERROR, 'No method found with name: ' + \
                    str(method_name))
               
    def register_rpcmethods(self, apps):
        '''
        Scans the installed apps for methods with the rpcmethod decorator
        Adds these methods to the list of methods callable via RPC
        '''    
        
        for appname in apps:
            # check each app for any rpcmethods
            app = __import__(appname, globals(), locals(), ['*'])
            for obj in dir(app):
                method = getattr(app, obj)
                if callable(method) and \
                   hasattr(method, 'is_rpcmethod'):
                    # if this method is callable and it has the rpcmethod
                    # decorator, add it to the dispatcher
                    self.register_method(method, method.external_name)
                elif isinstance(method, types.ModuleType):
                    # if this is not a method and instead a sub-module,
                    # scan the module for methods with @rpcmethod
                    try:
                        self.register_rpcmethods(["%s.%s" % (appname, obj)])
                    except ImportError:
                        pass

    
    def jsondispatch(self, raw_post_data, **kwargs):
        '''
        Sends the post data to a jsonrpc processor
        '''
        
        return self.jsonrpcdispatcher.dispatch(raw_post_data, **kwargs)
    
    def xmldispatch(self, raw_post_data, **kwargs):
        '''
        Sends the post data to an xmlrpc processor
        '''
        
        return self.xmlrpcdispatcher.dispatch(raw_post_data, **kwargs)
        
    def get_method_name(self, raw_post_data, request_format='xml'):
        '''
        Gets the name of the method to be called given the post data
        and the format of the data
        '''
        
        if request_format == 'xml':
            # xmlrpclib.loads could throw an exception, but this is fine
            # since _marshaled_dispatch would throw the same thing
            try:
                params, method = xmlrpclib.loads(raw_post_data)
                return method
            except Fault:
                return None
        else:
            try:
                # attempt to do a json decode on the data
                jsondict = json.loads(raw_post_data)
                if not isinstance(jsondict, dict) or 'method' not in jsondict:
                    return None
                else:
                    return jsondict['method']
            except ValueError:
                return None
        
    def list_methods(self):
        '''
        Returns a list of RPCMethod objects supported by the server
        '''
        
        return self.rpcmethods
    
    def register_method(self, method, name=None, signature=None, helpmsg=None):
        '''
        Registers a method with the rpc server
        '''

        meth = RPCMethod(method, name, signature, helpmsg)
        
        if meth.name not in self.system_listmethods():
            self.xmlrpcdispatcher.register_function(method, meth.name)
            self.jsonrpcdispatcher.register_function(method, meth.name)
            self.rpcmethods.append(meth)
class RPCDispatcher:
    '''
    Keeps track of the methods available to be called and then
    dispatches method calls to either the 
    :class:`XMLRPCDispatcher <rpc4django.xmlrpcdispatcher.XMLRPCDispatcher>`
    or the 
    :class:`JSONRPCDispatcher <rpc4django.jsonrpcdispatcher.JSONRPCDispatcher>`
    
    Disables RPC introspection methods (eg. ``system.list_methods()`` if 
    ``restrict_introspection`` is set to ``True``. Disables out of the box
    authentication if ``restrict_ootb_auth`` is ``True``.
    
    **Attributes**

    ``url``
      The URL that handles RPC requests (eg. ``/RPC2``)
      This is needed by ``system.describe``.
    ``rpcmethods``
      A list of :class:`RPCMethod<rpc4django.rpcdispatcher.RPCMethod>` instances
      available to be called by the dispatcher
    ``xmlrpcdispatcher``
      An instance of :class:`XMLRPCDispatcher <rpc4django.xmlrpcdispatcher.XMLRPCDispatcher>`
      where XMLRPC calls are dispatched to using :meth:`xmldispatch`
    ``jsonrpcdispatcher``
      An instance of :class:`JSONRPCDispatcher <rpc4django.jsonrpcdispatcher.JSONRPCDispatcher>`
      where JSONRPC calls are dispatched to using :meth:`jsondispatch`
      
    '''
    
    def __init__(self, url='', apps=[], restrict_introspection=False,
            restrict_ootb_auth=True, json_encoder=None):
        version = platform.python_version_tuple()
        self.url = url
        self.rpcmethods = []        # a list of RPCMethod objects
        self.jsonrpcdispatcher = JSONRPCDispatcher(json_encoder)
        self.xmlrpcdispatcher = XMLRPCDispatcher()
            
        if not restrict_introspection:
            self.register_method(self.system_listmethods)
            self.register_method(self.system_methodhelp)
            self.register_method(self.system_methodsignature)
            self.register_method(self.system_describe)
            
        if not restrict_ootb_auth:
            self.register_method(self.system_login)
            self.register_method(self.system_logout)
            
        self.register_rpcmethods(apps)
        
    @rpcmethod(name='system.describe', signature=['struct'])
    def system_describe(self):
        '''
        Returns a simple method description of the methods supported
        '''
        
        description = {}
        description['serviceType'] = 'RPC4Django JSONRPC+XMLRPC'
        description['serviceURL'] = self.url,
        description['methods'] = [{'name': method.name, 
                                   'summary': method.help, 
                                   'params': method.get_params(),
                                   'return': method.get_returnvalue()} \
                                  for method in self.rpcmethods]
        
        return description
    
    @rpcmethod(name='system.listMethods', signature=['array'])
    def system_listmethods(self):
        '''
        Returns a list of supported methods
        '''
        
        methods = [method.name for method in self.rpcmethods]
        methods.sort()
        return methods
    
    @rpcmethod(name='system.methodHelp', signature=['string', 'string'])
    def system_methodhelp(self, method_name):
        '''
        Returns documentation for a specified method
        '''
        
        for method in self.rpcmethods:
            if method.name == method_name:
                return method.help
            
        # this differs from what implementation in SimpleXMLRPCServer does
        # this will report via a fault or error while SimpleXMLRPCServer
        # just returns an empty string
        raise Fault(APPLICATION_ERROR, 'No method found with name: ' + \
                    str(method_name))
          
    @rpcmethod(name='system.methodSignature', signature=['array', 'string'])
    def system_methodsignature(self, method_name):
        '''
        Returns the signature for a specified method 
        '''
        
        for method in self.rpcmethods:
            if method.name == method_name:
                return method.signature
        raise Fault(APPLICATION_ERROR, 'No method found with name: ' + \
                    str(method_name))
    
    @rpcmethod(name='system.login', signature=['boolean', 'string', 'string'])
    def system_login(self, username, password, **kwargs):
        '''
        Authorizes a user to enable sending protected RPC requests
        '''
        
        request = kwargs.get('request', None)
        user = authenticate(username=username, password=password)
        
        if user is not None and request is not None:
            if user.is_active:
                login(request, user)
                return True
        
        return False
        
    @rpcmethod(name='system.logout', signature=['boolean'])
    def system_logout(self, **kwargs):
        '''
        Deauthorizes a user
        '''
        
        request = kwargs.get('request', None)
        
        if request is not None:
            logout(request)
            return True
            
        return False
               
    def register_rpcmethods(self, apps):
        '''
        Scans the installed apps for methods with the rpcmethod decorator
        Adds these methods to the list of methods callable via RPC
        '''    
        
        for appname in apps:
            # check each app for any rpcmethods
            try:
                app = __import__(appname, globals(), locals(), ['*'])
            except (ImportError, ValueError):
                # import throws ValueError on empty "name"
                continue

            for obj in dir(app):
                method = getattr(app, obj)
                if isinstance(method, xmlrpclib.ServerProxy):
                    continue
                if callable(method) and \
                   hasattr(method, 'is_rpcmethod') and \
                   method.is_rpcmethod == True:
                    # if this method is callable and it has the rpcmethod
                    # decorator, add it to the dispatcher
                    self.register_method(method, method.external_name)
                elif isinstance(method, types.ModuleType):
                    # if this is not a method and instead a sub-module,
                    # scan the module for methods with @rpcmethod
                    self.register_rpcmethods(["%s.%s" % (appname, obj)])
                        

    
    def jsondispatch(self, raw_post_data, **kwargs):
        '''
        Sends the post data to :meth:`rpc4django.jsonrpcdispatcher.JSONRPCDispatcher.dispatch`
        '''
        
        return self.jsonrpcdispatcher.dispatch(raw_post_data, **kwargs)
    
    def xmldispatch(self, raw_post_data, **kwargs):
        '''
        Sends the post data to :meth:`rpc4django.xmlrpcdispatcher.XMLRPCDispatcher.dispatch`
        '''
        
        return self.xmlrpcdispatcher.dispatch(raw_post_data, **kwargs)
        
    def get_method_name(self, raw_post_data, request_format='xml'):
        '''
        Gets the name of the method to be called given the post data
        and the format of the data
        '''
        
        if request_format == 'xml':
            # xmlrpclib.loads could throw an exception, but this is fine
            # since _marshaled_dispatch would throw the same thing
            try:
                params, method = xmlrpclib.loads(raw_post_data)
                return method
            except Exception:
                return None
        else:
            try:
                # attempt to do a json decode on the data
                jsondict = json.loads(raw_post_data)
                if not isinstance(jsondict, dict) or 'method' not in jsondict:
                    return None
                else:
                    return jsondict['method']
            except ValueError:
                return None
        
    def list_methods(self):
        '''
        Returns a list of RPCMethod objects supported by the server
        '''
        
        return self.rpcmethods
    
    def register_method(self, method, name=None, signature=None, helpmsg=None):
        '''
        Instantiates an RPCMethod object and adds it to ``rpcmethods``
        so that it can be called by RPC requests
        
        **Parameters**
        
        ``method``
          A callable Python method that the dispatcher will delegate to when
          requested via RPC
        ``name``
          The name to make the method availabe. ``None`` signifies to use
          the method's actual name
        ``signature``
          The signature of the method. See :meth:`rpc4django.rpcdispatcher.rpcmethod`
        ``helpmsg``
          The "help" message displayed by introspection functions asking about
          the method
          
        '''

        meth = RPCMethod(method, name, signature, helpmsg)
        
        if meth.name not in self.system_listmethods():
            self.xmlrpcdispatcher.register_function(method, meth.name)
            self.jsonrpcdispatcher.register_function(method, meth.name)
            self.rpcmethods.append(meth)
示例#9
0
class RPCDispatcher:
    """
    Dispatches method calls to either the xmlrpc or jsonrpc dispatcher
    """

    def __init__(self, url="", apps=[], restrict_introspection=False):
        version = platform.python_version_tuple()
        self.url = url
        self.rpcmethods = []  # a list of RPCMethod objects
        self.jsonrpcdispatcher = JSONRPCDispatcher()

        if int(version[0]) < 3 and int(version[1]) < 5:
            # this is for python 2.4 and below
            self.xmlrpcdispatcher = SimpleXMLRPCDispatcher()
        else:
            # python 2.5+ requires different parameters
            self.xmlrpcdispatcher = SimpleXMLRPCDispatcher(allow_none=False, encoding=None)

        if not restrict_introspection:
            self.register_method(self.system_listmethods)
            self.register_method(self.system_methodhelp)
            self.register_method(self.system_methodsignature)
            self.register_method(self.system_describe)

        self.register_rpcmethods(apps)

    @rpcmethod(name="system.describe", signature=["struct"])
    def system_describe(self):
        """
        Returns a simple method description of the methods supported
        """

        description = {}
        description["serviceType"] = "RPC4Django JSONRPC+XMLRPC"
        description["serviceURL"] = (self.url,)
        description["methods"] = [
            {
                "name": method.name,
                "summary": method.help,
                "params": method.get_params(),
                "return": method.get_returnvalue(),
            }
            for method in self.rpcmethods
        ]

        return description

    @rpcmethod(name="system.listMethods", signature=["array"])
    def system_listmethods(self):
        """
        Returns a list of supported methods
        """

        methods = [method.name for method in self.rpcmethods]
        methods.sort()
        return methods

    @rpcmethod(name="system.methodHelp", signature=["string", "string"])
    def system_methodhelp(self, method_name):
        """
        Returns documentation for a specified method
        """

        for method in self.rpcmethods:
            if method.name == method_name:
                return method.help

        # this differs from what implementation in SimpleXMLRPCServer does
        # this will report via a fault or error while SimpleXMLRPCServer
        # just returns an empty string
        raise Fault(APPLICATION_ERROR, "No method found with name: " + str(method_name))

    @rpcmethod(name="system.methodSignature", signature=["array", "string"])
    def system_methodsignature(self, method_name):
        """
        Returns the signature for a specified method 
        """

        for method in self.rpcmethods:
            if method.name == method_name:
                return method.signature
        raise Fault(APPLICATION_ERROR, "No method found with name: " + str(method_name))

    def register_rpcmethods(self, apps):
        """
        Scans the installed apps for methods with the rpcmethod decorator
        Adds these methods to the list of methods callable via RPC
        """

        for appname in apps:
            # check each app for any rpcmethods
            app = __import__(appname, globals(), locals(), ["*"])
            for obj in dir(app):
                method = getattr(app, obj)
                if callable(method) and getattr(method, "is_rpcmethod", False):
                    # if this method is callable and it has the rpcmethod
                    # decorator, add it to the dispatcher
                    self.register_method(method, method.external_name)

    def jsondispatch(self, raw_post_data):
        """
        Sends the post data to a jsonrpc processor
        """

        return self.jsonrpcdispatcher.dispatch(raw_post_data)

    def xmldispatch(self, raw_post_data):
        """
        Sends the post data to an xmlrpc processor
        """

        return self.xmlrpcdispatcher._marshaled_dispatch(raw_post_data)

    def get_method_name(self, raw_post_data, request_format="xml"):
        """
        Gets the name of the method to be called given the post data
        and the format of the data
        """

        if request_format == "xml":
            # xmlrpclib.loads could throw an exception, but this is fine
            # since _marshaled_dispatch would throw the same thing
            try:
                params, method = xmlrpclib.loads(raw_post_data)
                return method
            except Fault:
                return None
        else:
            try:
                # attempt to do a json decode on the data
                jsondict = json.loads(raw_post_data)
                if not isinstance(jsondict, dict) or "method" not in jsondict:
                    return None
                else:
                    return jsondict["method"]
            except ValueError:
                return None

    def list_methods(self):
        """
        Returns a list of RPCMethod objects supported by the server
        """

        return self.rpcmethods

    def register_method(self, method, name=None, signature=None, helpmsg=None):
        """
        Registers a method with the rpc server
        """

        meth = RPCMethod(method, name, signature, helpmsg)
        self.xmlrpcdispatcher.register_function(method, meth.name)
        self.jsonrpcdispatcher.register_function(method, meth.name)
        self.rpcmethods.append(meth)
示例#10
0
class RPCDispatcher:
    '''
    Keeps track of the methods available to be called and then
    dispatches method calls to
    :class:`JSONRPCDispatcher <rpc4django.jsonrpcdispatcher.JSONRPCDispatcher>`

    Disables RPC introspection methods (eg. ``system.list_methods()`` if
    ``restrict_introspection`` is set to ``True``. Disables out of the box
    authentication if ``restrict_ootb_auth`` is ``True``.

    **Attributes**

    ``url``
      The URL that handles RPC requests (eg. ``/RPC2``)
      This is needed by ``system.describe``.
    ``rpcmethods``
      A list of :class:`RPCMethod<rpc4django.rpcdispatcher.RPCMethod>` instances
      available to be called by the dispatcher
    ``jsonrpcdispatcher``
      An instance of :class:`JSONRPCDispatcher <rpc4django.jsonrpcdispatcher.JSONRPCDispatcher>`
      where JSONRPC calls are dispatched to using :meth:`jsondispatch`

    '''
    
    def __init__(self, url='', apps=[], restrict_introspection=False,
            restrict_ootb_auth=True, json_encoder=None):
        version = platform.python_version_tuple()
        self.url = url
        self.rpcmethods = []        # a list of RPCMethod objects
        self.jsonrpcdispatcher = JSONRPCDispatcher(json_encoder)

        if not restrict_introspection:
            self.register_method(self.system_listmethods)
            self.register_method(self.system_methodhelp)
            self.register_method(self.system_methodsignature)
            self.register_method(self.system_describe)

        if not restrict_ootb_auth:
            self.register_method(self.system_login)
            self.register_method(self.system_logout)

        self.register_rpcmethods(apps)


    def check_request_permission(self, request):
        '''
        Checks whether this user has permission to call a particular method
        This method does not check method call validity. That is done later

        **Parameters**

        - ``request`` - a django HttpRequest object

        Returns ``False`` if permission is denied and ``True`` otherwise
        '''
        methods = self.list_methods()
        method_name = self.get_method_name(request.raw_post_data) # TODO: put it to json dispatcher

        for method in methods:
            if method.name != method_name:
                continue

            if method.authentication:
                method.authentication(request)

            if method.authorization:
                method.authorization(request)

            return True

        # TODO raise wrong method


    @rpcmethod(name='system.describe', signature=['struct'])
    def system_describe(self, **kwargs):
        '''
        Returns a simple method description of the methods supported
        '''

        description = {}
        description['serviceType'] = 'RPC4Django JSONRPC'
        description['serviceURL'] = self.url,
        description['methods'] = [{'name': method.name,
                                   'summary': method.help,
                                   'params': method.get_params(),
                                   'return': method.get_returnvalue()} \
                                  for method in self.rpcmethods]

        return description

    @rpcmethod(name='system.listMethods', signature=['array'])
    def system_listmethods(self, **kwargs):
        '''
        Returns a list of supported methods
        '''

        methods = [method.name for method in self.rpcmethods]
        methods.sort()
        return methods

    @rpcmethod(name='system.methodHelp', signature=['string', 'string'])
    def system_methodhelp(self, method_name, **kwargs):
        '''
        Returns documentation for a specified method
        '''

        for method in self.rpcmethods:
            if method.name == method_name:
                return method.help

        raise BadMethodException('Method %s not registered here' % method_name)

    @rpcmethod(name='system.methodSignature', signature=['array', 'string'])
    def system_methodsignature(self, method_name, **kwargs):
        '''
        Returns the signature for a specified method
        '''

        for method in self.rpcmethods:
            if method.name == method_name:
                return method.signature

        raise BadMethodException('Method %s not registered here' % method_name)

    @rpcmethod(name='system.login', signature=['boolean', 'string', 'string'])
    def system_login(self, username, password, **kwargs):
        '''
        Authorizes a user to enable sending protected RPC requests
        '''

        request = kwargs.get('request', None)
        user = authenticate(username=username, password=password)

        if user is not None and request is not None:
            if user.is_active:
                login(request, user)
                return True

        return False

    @rpcmethod(name='system.logout', signature=['boolean'])
    def system_logout(self, **kwargs):
        '''
        Deauthorizes a user
        '''

        request = kwargs.get('request', None)

        if request is not None:
            logout(request)
            return True

        return False

    def register_rpcmethods(self, apps):
        '''
        Scans the installed apps for methods with the rpcmethod decorator
        Adds these methods to the list of methods callable via RPC
        '''

        for appname in apps:
            # check each app for any rpcmethods
            try:
                app = __import__(appname, globals(), locals(), ['*'])
            except (ImportError, ValueError):
                # import throws ValueError on empty "name"
                continue

            for obj in dir(app):
                method = getattr(app, obj)
                if callable(method) and \
                   hasattr(method, 'is_rpcmethod') and \
                   method.is_rpcmethod == True:
                    # if this method is callable and it has the rpcmethod
                    # decorator, add it to the dispatcher
                    self.register_method(method, method.external_name)
                elif isinstance(method, types.ModuleType):
                    # if this is not a method and instead a sub-module,
                    # scan the module for methods with @rpcmethod
                    self.register_rpcmethods(["%s.%s" % (appname, obj)])


    def get_method_name(self, raw_post_data):
        '''
        Gets the name of the method to be called given the post data
        and the format of the data
        '''
        try:
            # attempt to do a json decode on the data
            jsondict = json.loads(raw_post_data)
            if not isinstance(jsondict, dict) or 'method' not in jsondict:
                return None
            else:
                return jsondict['method']
        except ValueError:
            return None

    def list_methods(self):
        '''
        Returns a list of RPCMethod objects supported by the server
        '''

        return self.rpcmethods

    def register_method(self, method, name=None, signature=None, helpmsg=None):
        '''
        Instantiates an RPCMethod object and adds it to ``rpcmethods``
        so that it can be called by RPC requests

        **Parameters**

        ``method``
          A callable Python method that the dispatcher will delegate to when
          requested via RPC
        ``name``
          The name to make the method availabe. ``None`` signifies to use
          the method's actual name
        ``signature``
          The signature of the method. See :meth:`rpc4django.rpcdispatcher.rpcmethod`
        ``helpmsg``
          The "help" message displayed by introspection functions asking about
          the method

        '''

        meth = RPCMethod(method, name, signature, helpmsg)

        if meth.name not in self.system_listmethods():
            self.jsonrpcdispatcher.register_function(method, meth.name)
            self.rpcmethods.append(meth)
示例#11
0
class RPCDispatcher:
    '''
    Keeps track of the methods available to be called and then
    dispatches method calls to either the
    :class:`XMLRPCDispatcher <rpc4django.xmlrpcdispatcher.XMLRPCDispatcher>`
    or the
    :class:`JSONRPCDispatcher <rpc4django.jsonrpcdispatcher.JSONRPCDispatcher>`

    Disables RPC introspection methods (eg. ``system.list_methods()`` if
    ``restrict_introspection`` is set to ``True``. Disables out of the box
    authentication if ``restrict_ootb_auth`` is ``True``.

    **Attributes**

    ``url``
      The URL that handles RPC requests (eg. ``/RPC2``)
      This is needed by ``system.describe``.
    ``rpcmethods``
      A list of :class:`RPCMethod<rpc4django.rpcdispatcher.RPCMethod>` instances
      available to be called by the dispatcher
    ``xmlrpcdispatcher``
      An instance of :class:`XMLRPCDispatcher <rpc4django.xmlrpcdispatcher.XMLRPCDispatcher>`
      where XMLRPC calls are dispatched to using :meth:`xmldispatch`
    ``jsonrpcdispatcher``
      An instance of :class:`JSONRPCDispatcher <rpc4django.jsonrpcdispatcher.JSONRPCDispatcher>`
      where JSONRPC calls are dispatched to using :meth:`jsondispatch`

    '''
    def __init__(self,
                 url='',
                 apps=[],
                 restrict_introspection=False,
                 restrict_ootb_auth=True):
        version = platform.python_version_tuple()
        self.url = url
        self.rpcmethods = []  # a list of RPCMethod objects
        self.jsonrpcdispatcher = JSONRPCDispatcher()
        self.xmlrpcdispatcher = XMLRPCDispatcher()

        if not restrict_introspection:
            self.register_method(self.system_listmethods)
            self.register_method(self.system_methodhelp)
            self.register_method(self.system_methodsignature)
            self.register_method(self.system_describe)

        if not restrict_ootb_auth:
            self.register_method(self.system_login)
            self.register_method(self.system_logout)

        self.register_rpcmethods(apps)

    @rpcmethod(name='system.describe', signature=['struct'])
    def system_describe(self):
        '''
        Returns a simple method description of the methods supported
        '''

        description = {}
        description['serviceType'] = 'RPC4Django JSONRPC+XMLRPC'
        description['serviceURL'] = self.url,
        description['methods'] = [{'name': method.name,
                                   'summary': method.help,
                                   'params': method.get_params(),
                                   'return': method.get_returnvalue()} \
                                  for method in self.rpcmethods]

        return description

    @rpcmethod(name='system.listMethods', signature=['array'])
    def system_listmethods(self):
        '''
        Returns a list of supported methods
        '''

        methods = [method.name for method in self.rpcmethods]
        methods.sort()
        return methods

    @rpcmethod(name='system.methodHelp', signature=['string', 'string'])
    def system_methodhelp(self, method_name):
        '''
        Returns documentation for a specified method
        '''

        for method in self.rpcmethods:
            if method.name == method_name:
                return method.help

        # this differs from what implementation in SimpleXMLRPCServer does
        # this will report via a fault or error while SimpleXMLRPCServer
        # just returns an empty string
        raise Fault(APPLICATION_ERROR, 'No method found with name: ' + \
                    str(method_name))

    @rpcmethod(name='system.methodSignature', signature=['array', 'string'])
    def system_methodsignature(self, method_name):
        '''
        Returns the signature for a specified method
        '''

        for method in self.rpcmethods:
            if method.name == method_name:
                return method.signature
        raise Fault(APPLICATION_ERROR, 'No method found with name: ' + \
                    str(method_name))

    @rpcmethod(name='system.login', signature=['boolean', 'string', 'string'])
    def system_login(self, username, password, **kwargs):
        '''
        Authorizes a user to enable sending protected RPC requests
        '''

        request = kwargs.get('request', None)
        user = authenticate(username=username, password=password)

        if user is not None and request is not None:
            if user.is_active:
                login(request, user)
                return True

        return False

    @rpcmethod(name='system.logout', signature=['boolean'])
    def system_logout(self, **kwargs):
        '''
        Deauthorizes a user
        '''

        request = kwargs.get('request', None)

        if request is not None:
            logout(request)
            return True

        return False

    def register_rpcmethods(self, apps):
        '''
        Scans the installed apps for methods with the rpcmethod decorator
        Adds these methods to the list of methods callable via RPC
        '''

        for appname in apps:
            # check each app for any rpcmethods
            try:
                app = __import__(appname, globals(), locals(), ['*'])
            except (ImportError, ValueError):
                # import throws ValueError on empty "name"
                continue

            for obj in dir(app):
                method = getattr(app, obj)
                if isinstance(method, xmlrpclib.ServerProxy):
                    continue
                if callable(method) and \
                   hasattr(method, 'is_rpcmethod') and \
                   method.is_rpcmethod == True:
                    # if this method is callable and it has the rpcmethod
                    # decorator, add it to the dispatcher
                    self.register_method(method, method.external_name)
                elif isinstance(method, types.ModuleType):
                    # if this is not a method and instead a sub-module,
                    # scan the module for methods with @rpcmethod
                    self.register_rpcmethods(["%s.%s" % (appname, obj)])

    def jsondispatch(self, raw_post_data, **kwargs):
        '''
        Sends the post data to :meth:`rpc4django.jsonrpcdispatcher.JSONRPCDispatcher.dispatch`
        '''

        return self.jsonrpcdispatcher.dispatch(raw_post_data, **kwargs)

    def xmldispatch(self, raw_post_data, **kwargs):
        '''
        Sends the post data to :meth:`rpc4django.xmlrpcdispatcher.XMLRPCDispatcher.dispatch`
        '''

        return self.xmlrpcdispatcher.dispatch(raw_post_data, **kwargs)

    def get_method_name(self, raw_post_data, request_format='xml'):
        '''
        Gets the name of the method to be called given the post data
        and the format of the data
        '''

        if request_format == 'xml':
            # xmlrpclib.loads could throw an exception, but this is fine
            # since _marshaled_dispatch would throw the same thing
            try:
                params, method = xmlrpclib.loads(raw_post_data)
                return method
            except Exception:
                return None
        else:
            try:
                # attempt to do a json decode on the data
                jsondict = json.loads(raw_post_data)
                if not isinstance(jsondict, dict) or 'method' not in jsondict:
                    return None
                else:
                    return jsondict['method']
            except ValueError:
                return None

    def list_methods(self):
        '''
        Returns a list of RPCMethod objects supported by the server
        '''

        return self.rpcmethods

    def register_method(self, method, name=None, signature=None, helpmsg=None):
        '''
        Instantiates an RPCMethod object and adds it to ``rpcmethods``
        so that it can be called by RPC requests

        **Parameters**

        ``method``
          A callable Python method that the dispatcher will delegate to when
          requested via RPC
        ``name``
          The name to make the method availabe. ``None`` signifies to use
          the method's actual name
        ``signature``
          The signature of the method. See :meth:`rpc4django.rpcdispatcher.rpcmethod`
        ``helpmsg``
          The "help" message displayed by introspection functions asking about
          the method

        '''

        meth = RPCMethod(method, name, signature, helpmsg)

        if meth.name not in self.system_listmethods():
            self.xmlrpcdispatcher.register_function(method, meth.name)
            self.jsonrpcdispatcher.register_function(method, meth.name)
            self.rpcmethods.append(meth)
示例#12
0
class RPCDispatcher:
    '''
    Dispatches method calls to either the xmlrpc or jsonrpc dispatcher
    '''
    
    def __init__(self, url_name='root', restrict_introspection=False):
        self.url_name = url_name
        self.rpcmethods = []        # a list of RPCMethod objects
        self.jsonrpcdispatcher = JSONRPCDispatcher()
        self.xmlrpcdispatcher = XMLRPCDispatcher()
            
        if not restrict_introspection:
            self.register_method(self.system_listmethods)
            self.register_method(self.system_methodhelp)
            self.register_method(self.system_methodsignature)
            self.register_method(self.system_describe)
        
    @rpcmethod(name='system.describe', signature=['struct'])
    def system_describe(self):
        '''
        Returns a simple method description of the methods supported
        '''
        
        description = {}
        description['serviceType'] = 'RPC4Django JSONRPC+XMLRPC'
        description['methods'] = [{'name': method.name, 
                                   'summary': method.help, 
                                   'params': method.get_params(),
                                   'return': method.get_returnvalue()} \
                                  for method in self.rpcmethods]
        
        return description
    
    @rpcmethod(name='system.listMethods', signature=['array'])
    def system_listmethods(self):
        '''
        Returns a list of supported methods
        '''
        
        methods = [method.name for method in self.rpcmethods]
        methods.sort()
        return methods
    
    @rpcmethod(name='system.methodHelp', signature=['string', 'string'])
    def system_methodhelp(self, method_name):
        '''
        Returns documentation for a specified method
        '''
        
        for method in self.rpcmethods:
            if method.name == method_name:
                return method.help
            
        # this differs from what implementation in SimpleXMLRPCServer does
        # this will report via a fault or error while SimpleXMLRPCServer
        # just returns an empty string
        raise Fault(APPLICATION_ERROR, 'No method found with name: ' + \
                    str(method_name))
          
    @rpcmethod(name='system.methodSignature', signature=['array', 'string'])
    def system_methodsignature(self, method_name):
        '''
        Returns the signature for a specified method 
        '''
        
        for method in self.rpcmethods:
            if method.name == method_name:
                return method.signature
        raise Fault(APPLICATION_ERROR, 'No method found with name: ' + \
                    str(method_name))
               
    def jsondispatch(self, raw_post_data, **kwargs):
        '''
        Sends the post data to a jsonrpc processor
        '''
        
        return self.jsonrpcdispatcher.dispatch(raw_post_data, **kwargs)
    
    def xmldispatch(self, raw_post_data, **kwargs):
        '''
        Sends the post data to an xmlrpc processor
        '''
        
        return self.xmlrpcdispatcher.dispatch(raw_post_data, **kwargs)
        
    def get_method_name(self, raw_post_data, request_format='xml'):
        '''
        Gets the name of the method to be called given the post data
        and the format of the data
        '''
        
        if request_format == 'xml':
            # xmlrpclib.loads could throw an exception, but this is fine
            # since _marshaled_dispatch would throw the same thing
            try:
                params, method = xmlrpclib.loads(raw_post_data)
                return method
            except Fault:
                return None
        else:
            try:
                # attempt to do a json decode on the data
                jsondict = json.loads(raw_post_data)
                if not isinstance(jsondict, dict) or 'method' not in jsondict:
                    return None
                else:
                    return jsondict['method']
            except ValueError:
                return None
        
    def list_methods(self):
        '''
        Returns a list of RPCMethod objects supported by the server
        '''
        
        return self.rpcmethods
    
    def register_method(self, method, name=None, signature=None, helpmsg=None):
        '''
        Registers a method with the rpc server
        '''

        meth = RPCMethod(method, name, signature, helpmsg)
        
        if meth.name not in self.system_listmethods():
            self.xmlrpcdispatcher.register_function(method, meth.name)
            self.jsonrpcdispatcher.register_function(method, meth.name)
            self.rpcmethods.append(meth)
示例#13
0
class RPCDispatcher:
    '''
    Dispatches method calls to either the xmlrpc or jsonrpc dispatcher
    '''
    def __init__(self, url='', apps=[], restrict_introspection=False):
        version = platform.python_version_tuple()
        self.url = url
        self.rpcmethods = []  # a list of RPCMethod objects
        self.jsonrpcdispatcher = JSONRPCDispatcher()
        self.xmlrpcdispatcher = XMLRPCDispatcher()

        if not restrict_introspection:
            self.register_method(self.system_listmethods)
            self.register_method(self.system_methodhelp)
            self.register_method(self.system_methodsignature)
            self.register_method(self.system_describe)

        self.register_rpcmethods(apps)

    @rpcmethod(name='system.describe', signature=['struct'])
    def system_describe(self):
        '''
        Returns a simple method description of the methods supported
        '''

        description = {}
        description['serviceType'] = 'RPC4Django JSONRPC+XMLRPC'
        description['serviceURL'] = self.url,
        description['methods'] = [{'name': method.name,
                                   'summary': method.help,
                                   'params': method.get_params(),
                                   'return': method.get_returnvalue()} \
                                  for method in self.rpcmethods]

        return description

    @rpcmethod(name='system.listMethods', signature=['array'])
    def system_listmethods(self):
        '''
        Returns a list of supported methods
        '''

        methods = [method.name for method in self.rpcmethods]
        methods.sort()
        return methods

    @rpcmethod(name='system.methodHelp', signature=['string', 'string'])
    def system_methodhelp(self, method_name):
        '''
        Returns documentation for a specified method
        '''

        for method in self.rpcmethods:
            if method.name == method_name:
                return method.help

        # this differs from what implementation in SimpleXMLRPCServer does
        # this will report via a fault or error while SimpleXMLRPCServer
        # just returns an empty string
        raise Fault(APPLICATION_ERROR, 'No method found with name: ' + \
                    str(method_name))

    @rpcmethod(name='system.methodSignature', signature=['array', 'string'])
    def system_methodsignature(self, method_name):
        '''
        Returns the signature for a specified method 
        '''

        for method in self.rpcmethods:
            if method.name == method_name:
                return method.signature
        raise Fault(APPLICATION_ERROR, 'No method found with name: ' + \
                    str(method_name))

    def register_rpcmethods(self, apps):
        '''
        Scans the installed apps for methods with the rpcmethod decorator
        Adds these methods to the list of methods callable via RPC
        '''

        for appname in apps:
            # check each app for any rpcmethods
            app = __import__(appname, globals(), locals(), ['*'])
            for obj in dir(app):
                method = getattr(app, obj)
                if callable(method) and \
                   hasattr(method, 'is_rpcmethod'):
                    # if this method is callable and it has the rpcmethod
                    # decorator, add it to the dispatcher
                    self.register_method(method, method.external_name)
                elif isinstance(method, types.ModuleType):
                    # if this is not a method and instead a sub-module,
                    # scan the module for methods with @rpcmethod
                    try:
                        self.register_rpcmethods(["%s.%s" % (appname, obj)])
                    except ImportError:
                        pass

    def jsondispatch(self, raw_post_data, **kwargs):
        '''
        Sends the post data to a jsonrpc processor
        '''

        return self.jsonrpcdispatcher.dispatch(raw_post_data, **kwargs)

    def xmldispatch(self, raw_post_data, **kwargs):
        '''
        Sends the post data to an xmlrpc processor
        '''

        return self.xmlrpcdispatcher.dispatch(raw_post_data, **kwargs)

    def get_method_name(self, raw_post_data, request_format='xml'):
        '''
        Gets the name of the method to be called given the post data
        and the format of the data
        '''

        if request_format == 'xml':
            # xmlrpclib.loads could throw an exception, but this is fine
            # since _marshaled_dispatch would throw the same thing
            try:
                params, method = xmlrpclib.loads(raw_post_data)
                return method
            except Fault:
                return None
        else:
            try:
                # attempt to do a json decode on the data
                jsondict = json.loads(raw_post_data)
                if not isinstance(jsondict, dict) or 'method' not in jsondict:
                    return None
                else:
                    return jsondict['method']
            except ValueError:
                return None

    def list_methods(self):
        '''
        Returns a list of RPCMethod objects supported by the server
        '''

        return self.rpcmethods

    def register_method(self, method, name=None, signature=None, helpmsg=None):
        '''
        Registers a method with the rpc server
        '''

        meth = RPCMethod(method, name, signature, helpmsg)

        if meth.name not in self.system_listmethods():
            self.xmlrpcdispatcher.register_function(method, meth.name)
            self.jsonrpcdispatcher.register_function(method, meth.name)
            self.rpcmethods.append(meth)
示例#14
0
class RPCDispatcher:
    '''
    Dispatches method calls to either the xmlrpc or jsonrpc dispatcher
    '''
    def __init__(self, url_name='root', restrict_introspection=False):
        self.url_name = url_name
        self.rpcmethods = []  # a list of RPCMethod objects
        self.jsonrpcdispatcher = JSONRPCDispatcher()
        self.xmlrpcdispatcher = XMLRPCDispatcher()

        if not restrict_introspection:
            self.register_method(self.system_listmethods)
            self.register_method(self.system_methodhelp)
            self.register_method(self.system_methodsignature)
            self.register_method(self.system_describe)

    @rpcmethod(name='system.describe', signature=['struct'])
    def system_describe(self):
        '''
        Returns a simple method description of the methods supported
        '''

        description = {}
        description['serviceType'] = 'RPC4Django JSONRPC+XMLRPC'
        description['methods'] = [{'name': method.name,
                                   'summary': method.help,
                                   'params': method.get_params(),
                                   'return': method.get_returnvalue()} \
                                  for method in self.rpcmethods]

        return description

    @rpcmethod(name='system.listMethods', signature=['array'])
    def system_listmethods(self):
        '''
        Returns a list of supported methods
        '''

        methods = [method.name for method in self.rpcmethods]
        methods.sort()
        return methods

    @rpcmethod(name='system.methodHelp', signature=['string', 'string'])
    def system_methodhelp(self, method_name):
        '''
        Returns documentation for a specified method
        '''

        for method in self.rpcmethods:
            if method.name == method_name:
                return method.help

        # this differs from what implementation in SimpleXMLRPCServer does
        # this will report via a fault or error while SimpleXMLRPCServer
        # just returns an empty string
        raise Fault(APPLICATION_ERROR, 'No method found with name: ' + \
                    str(method_name))

    @rpcmethod(name='system.methodSignature', signature=['array', 'string'])
    def system_methodsignature(self, method_name):
        '''
        Returns the signature for a specified method 
        '''

        for method in self.rpcmethods:
            if method.name == method_name:
                return method.signature
        raise Fault(APPLICATION_ERROR, 'No method found with name: ' + \
                    str(method_name))

    def jsondispatch(self, raw_post_data, **kwargs):
        '''
        Sends the post data to a jsonrpc processor
        '''

        return self.jsonrpcdispatcher.dispatch(raw_post_data, **kwargs)

    def xmldispatch(self, raw_post_data, **kwargs):
        '''
        Sends the post data to an xmlrpc processor
        '''

        return self.xmlrpcdispatcher.dispatch(raw_post_data, **kwargs)

    def get_method_name(self, raw_post_data, request_format='xml'):
        '''
        Gets the name of the method to be called given the post data
        and the format of the data
        '''

        if request_format == 'xml':
            # xmlrpclib.loads could throw an exception, but this is fine
            # since _marshaled_dispatch would throw the same thing
            try:
                params, method = xmlrpclib.loads(raw_post_data)
                return method
            except Fault:
                return None
        else:
            try:
                # attempt to do a json decode on the data
                jsondict = json.loads(raw_post_data)
                if not isinstance(jsondict, dict) or 'method' not in jsondict:
                    return None
                else:
                    return jsondict['method']
            except ValueError:
                return None

    def list_methods(self):
        '''
        Returns a list of RPCMethod objects supported by the server
        '''

        return self.rpcmethods

    def register_method(self, method, name=None, signature=None, helpmsg=None):
        '''
        Registers a method with the rpc server
        '''

        meth = RPCMethod(method, name, signature, helpmsg)

        if meth.name not in self.system_listmethods():
            self.xmlrpcdispatcher.register_function(method, meth.name)
            self.jsonrpcdispatcher.register_function(method, meth.name)
            self.rpcmethods.append(meth)