view doc/xmlrpc.txt @ 6915:9ff091537f43

postgresql native-fts; more indexer tests 1) Make postgresql native-fts actually work. 2) Add simple stopword filtering to sqlite native-fts indexer. 3) Add more tests for indexer_common get_indexer Details: 1) roundup/backends/indexer_postgresql_fts.py: ignore ValueError raised if we try to index a string with a null character in it. This could happen due to an incorrect text/ mime type on a file that has nulls in it. Replace ValueError raised by postgresql with customized IndexerQueryError if a search string has a null in it. roundup/backends/rdbms_common.py: Make postgresql native-fts work. When specified it was using using whatever was returned from get_indexer(). However loading the native-fts indexer backend failed because there was no connection to the postgresql database when this call was made. Simple solution, move the call after the open_connection call in Database::__init__(). However the open_connection call creates the schema for the database if it is not there. The schema builds tables for indexer=native type indexing. As part of the build it looks at the indexer to see the min/max size of the indexed tokens. No indexer define, we get a crash. So it's a a chicken/egg issue. I solved it by setting the indexer to the Indexer from indexer_common which has the min/max token size info. I also added a no-op save_indexer to this Indexer class. I claim save_indexer() isn't needed as a commit() on the db does all the saving required. Then after open_connection is called, I call get_indexer to retrieve the correct indexer and indexer_postgresql_fts woks since the conn connection property is defined. roundup/backends/indexer_common.py: add save_index() method for indexer. It does nothing but is needed in rdbms backends during schema initialization. 2) roundup/backends/indexer_sqlite_fts.py: when this indexer is used, the indexer test in DBTest on the word "the" fail. This is due to missing stopword filtering. Implement basic stopword filtering for bare stopwords (like 'the') to make the test pass. Note: this indexer is not currently automatically run by the CI suite, it was found during manual testing. However there is a FIXME to extract the indexer tests from DBTest and run it using this backend. roundup/configuration.py, roundup/doc/admin_guide.txt: update doc on stopword use for sqlite native-fts. test/db_test_base.py: DBTest::testStringBinary creates a file with nulls in it. It was breaking postgresql with native-fts indexer. Changed test to assign mime type application/octet-stream that prevents it from being processed by any text search indexer. add test to exclude indexer searching in specific props. This code path was untested before. test/test_indexer.py: add test to call find with no words. Untested code path. add test to index and find a string with a null \x00 byte. it was tested inadvertently by testStringBinary but this makes it explicit and moves it to indexer testing. (one version each for: generic, postgresql and mysql) Renamed Get_IndexerAutoSelectTest to Get_IndexerTest and renamed autoselect tests to include autoselect. Added tests for an invalid indexer and using native-fts with anydbm (unsupported combo) to make sure the code does something useful if the validation in configuration.py is broken. test/test_liveserver.py: add test to load an issue add test using text search (fts) to find the issue add tests to find issue using postgresql native-fts test/test_postgresql.py, test/test_sqlite.py: added explanation on how to setup integration test using native-fts. added code to clean up test environment if native-fts test is run.
author John Rouillard <rouilj@ieee.org>
date Mon, 05 Sep 2022 16:25:20 -0400
parents e7b4ad2c57ac
children db58a86aa29d
line wrap: on
line source

.. meta::
    :description:
        Documentation on the XMLRPC interface to the Roundup Issue
	Tracker. Includes sample clients.

.. index:: triple: api; xml; remote procedure call
   pair: api; xmlrpc

=========================
XML-RPC access to Roundup
=========================

.. contents::
   :local:

Introduction
------------
Version 1.4 of Roundup includes an XML-RPC frontend for remote access. The
XML-RPC interface allows a limited subset of commands similar to those found in
local `roundup-admin` tool.

By default XML-RPC is accessible from ``/xmlrpc`` endpoint:

    http://username:password@localhost:8000/xmlrpc

For demo tracker the URL would be:

    http://localhost:8917/demo/xmlrpc

Enabling XML-RPC server 
-----------------------
There are two ways to run the XML-RPC interface:

  through roundup itself

  stand alone roundup-xmlrpc-server


through roundup
---------------
The XML-RPC service is available from the roundup HTTP server under
/xmlrpc.

To enable this set ``enable_xmlrpc`` to ``yes`` in the ``[web]``
section of the ``config.ini`` file in your tracker.

Each user that needs access must include the "Xmlrpc Access" role. To
add this new permission to the "User" role you should change your
schema.py to add::

    db.security.addPermissionToRole('User', 'Xmlrpc Access')

This is usually included near where other permissions like "Web Access"
or "Email Access" are assigned.

stand alone roundup-xmlrpc-server
---------------------------------
Using roundup to access the xmlrpc interface is preferred. Roundup
provides better control over who can use the interface.

The Roundup XML-RPC standalone server must be started before remote
clients can access the tracker via XML-RPC. ``roundup-xmlrpc-server``
is installed in the scripts directory alongside ``roundup-server`` and
``roundup-admin``. When invoked, the location of the tracker instance
must be specified.

	roundup-xmlrpc-server -i ``/path/to/tracker``

The default port is ``8000``. An alternative port can be specified with the
``--port`` switch.

security consideration
----------------------
Both the standalone and embedded roundup XML endpoints used the
default python XML parser. This parser is know to have security
issues. For details see: https://pypi.org/project/defusedxml/.
You may wish to use the rest interface which doesn't have the same
issues. Patches with tests to roundup to use defusedxml are welcome.

Note that the current ``roundup-xmlrpc-server`` implementation does
not support SSL. This means that usernames and passwords will be
passed in cleartext unless the server is being proxied behind another
server (such as Apache or lighttpd) that provide SSL.

Client API
----------
The server currently implements seven methods/commands. Each method
requires that the user provide a username and password in the HTTP
authorization header in order to authenticate the request against the
tracker.

======= ====================================================================
Command Description
======= ====================================================================
schema

        Fetch tracker schema.

list    arguments: *classname, [property_name]*

        List all elements of a given ``classname``. If ``property_name`` is
        specified, that is the property that will be displayed for each
        element. If ``property_name`` is not specified the default label
        property will be used.

display arguments: *designator, [property_1, ..., property_N]*

        Display a single item in the tracker as specified by ``designator``
        (e.g. issue20 or user5). The default is to display all properties
        for the item. Alternatively, a list of properties to display can be
        specified.

create  arguments: *classname, arg_1 ... arg_N*

        Create a new instance of ``classname`` with ``arg_1`` through
        ``arg_N`` as the values of the new instance. The arguments are
        name=value pairs (e.g. ``status='3'``).

set     arguments: *designator, arg_1 ... arg_N*

        Set the values of an existing item in the tracker as specified by
        ``designator``. The new values are specified in ``arg_1`` through
        ``arg_N``. The arguments are name=value pairs (e.g. ``status='3'``).

lookup  arguments: *classname, key_value*

        looks up the key_value for the given class. The class needs to
        have a key and the user needs search permission on the key
        attribute and id for the given classname.

filter  arguments: *classname, list or None, attributes*
        
        ``list`` is a list of ids to filter. It can be set to None to run
        filter over all values (requires ``allow_none=True`` when
        instantiating the ServerProxy). The ``attributes`` are given as a 
        dictionary of name value pairs to search for. See also
        :ref:`query-tracker`.
======= ====================================================================

sample python client
====================

This client will work if you turn off the x-requested-with header and
the only CSRF header check you require is the HTTP host header::

        >>> import xmlrpclib
        >>> roundup_server = xmlrpclib.ServerProxy('http://admin:admin@localhost:8917/demo/xmlrpc', allow_none=True)
        >>> roundup_server.schema()
        {'user': [['username', '<roundup.hyperdb.String>'], ...], 'issue': [...]}
        >>> roundup_server.list('user')
        ['admin', 'anonymous', 'demo']
        >>> roundup_server.list('issue', 'id')
        ['1']
        >>> roundup_server.display('issue1')
        {'assignedto' : None, 'files' : [], 'title' = 'yes, ..... }
        >>> roundup_server.display('issue1', 'priority', 'status')
        {'priority' : '1', 'status' : '2'}
        >>> roundup_server.set('issue1', 'status=3')
        >>> roundup_server.display('issue1', 'status')
        {'status' : '3' }
        >>> roundup_server.create('issue', "title='another bug'", "status=2")
        '2'
        >>> roundup_server.filter('user',None,{'username':'adm'})
        ['1']
        >>> roundup_server.filter('user',['1','2'],{'username':'adm'})
        ['1']
        >>> roundup_server.filter('user',['2'],{'username':'adm'})
        []
        >>> roundup_server.filter('user',[],{'username':'adm'})
        []
        >>> roundup_server.lookup('user','admin')
        '1'

advanced python client adding anti-csrf headers
===============================================

The one below adds Referer and X-Requested-With headers so it can pass
stronger CSRF detection methods. It also generates a fault message
from the server and reports it. Note if you are using http rather than
https, replace xmlrpclib.SafeTransport with xmlrpclib.Transport::

    try:
        from xmlrpc import client as xmlrpclib  # python 3
    except ImportError:
        import xmlrpclib  # python 2

    hostname="localhost"
    path="/demo"
    user_pw="admin:admin"

    class SpecialTransport(xmlrpclib.SafeTransport):

        def send_content(self, connection, request_body):

            connection.putheader("Referer", "https://%s%s/"%(hostname, path))
            connection.putheader("Origin", "https://%s"%hostname)
            connection.putheader("X-Requested-With", "XMLHttpRequest")

            connection.putheader("Content-Type", "text/xml")    
            connection.putheader("Content-Length", str(len(request_body)))
            connection.endheaders()
            if request_body:
                connection.send(request_body)

    roundup_server = xmlrpclib.ServerProxy(
        'https://%s@%s%s/xmlrpc'%(user_pw,hostname,path),
        transport=SpecialTransport(),
        verbose=False,
        allow_none=True)

    print(roundup_server.schema())
    print(roundup_server.display('user2', 'username'))
    print(roundup_server.display('issue1', 'status'))
    print(roundup_server.filter('user',['1','2','3'],{'username':'demo'}))

    # this will fail with a fault
    try:
        print(roundup_server.filter('usr',['0','2','3'],{'username':'demo'}))
    except Exception as msg:
        print(msg)

modify this script replacing the hostname, path and user_pw with those
for your tracker.

Roundup Issue Tracker: http://roundup-tracker.org/