Introduction

This document describes the protocol used to interact between the Cerebrum administration server and its clients.

The protocol is based on TCP/IP, and servers implementing it are listening on port XYZ.

This is work in progress

Request -> response protocol

In this protocol, the client is allowed to send messages, which the server replies to. The server does not explicitly contact the client on its own.

Protocol encoding

Messages and responses are implemented using XML-RPC, an open standard that allows clients to call methods on a server. The method calls and the return values are encoded as XML. All of this is automatically handled by xmlrpclib which is included in Python.

XML-RPC was originally built for HTTP, but can also be used on top of other protocols.

XML-RPC over HTTPS

The request->response behavior of a typical bofh client makes HTTP a suitable protocol for transfer of the XML-RPC messages. However, for security reasons, HTTPS is used.

In the future, we might decide to use another transfer protocol. This should only require minor changes to clients/servers.

It is legal for the client to have multiple requests running at the same time with the same sessionid.

Character encoding

Methods

The return values of XML-RPC callable methods can among other things be dictionaries, lists strings and integers.

As the server is extend-able by modules all methods will not be described here. Use the python help function for a list of callable methods in a given module.

When an error occurs, a xmlrpclib.Fault is raised with the message parameter describing the cause of the error.

TODO

We might want to do something more fancy to fake various kinds of exceptions, useful exceptions could be: This would probably requiring clients to wrap the calls to the server methods so that xmlrpclib.Fault could be converted to something else. HOW?

login(uname, password)

sessid = testsvr.login(user, passwd)
The login method authenticates the user. Upon success, a sessionid is returned which must be used for future communication with the server.

helo(clientid)

All clients must call this function before they do anything else (can we enforce this?). Returns the string OK, NUMBER, server-version where NUMBER currently is 1. This number may be increased at a later time if the protocol is changed in an uncompatible way.

clientid is a string identifying the client. By requiring this string it is easier to keep track of the number of different clients.

get_commands(sessionid)

This command returns a tuple of tuples describing the commands available in the server for the user with the corresponding sessionid. The format of the data is as follows:
 
#   protocol_command  bofh_cmd1 bofh_cmd2 parameter[1..n] #of_loopable_param
commands = (
    ('get_person', 'person', 'get', 'number', 1),
    ('add_fg', 'filegroup', 'add', 'string', 'string', 1))
Here protocol_command is the name of the function that will be called in the server. bofh_cmd1 and bofh_cmd2 are the keywords that uniqualy identifies this command. parameter[1..n] indicates the expected type of the parameter. Legal types are: The last number is only used by the client to make it able to encode multiple server commands from one user command if the user wants to perform the same action on multiple targets. In the example above, if the user typed: filegroup add user1 user2 group, the client should send:
add_fg(user1, group)
add_fg(user2, group)

validate(argtype, arg)

if validate('fodselsnr', 12345678901):
Validates that arg is legal for the given argtype, and returns 1 on success, otherwise raises an error. The defined argtypes are: See the server source code for a complete list.

help(keyword)

Returns a string with help for the given keyword

run_command(sessionid, *args)

Calls one of the methods returned from get_commands(). See the help for the given method for parameters and return values.

The usage of run_command() as a wrapper for all other functions allows centralized handling of some authenticaion logic and any server messages (see below). One might argue that the methods should be exported directly, but this will put a greater burden on the server implementator not to accidentaly make it possible to call methods without being authenticated.

Extension to the run_command() return values

The server may wish to notify the client of an event. Since the server cannot send messages to the client, all responses to the run_command() are prepended with a server_msg.
server_msg, ret_value = server.function()
The legal values for server_msg are:

Extending bofhd.py

config.dat contains a list of the modules that should be loaded into bofhd. It contains a number of lines of the format:
module_file
module_file does not have a .py ending, and must contain a class named BofhdExtention.

The following methods must be implemented (see bofhd_module_example.py for an example):

def __init__(self):

    # The format of the all_commands dict is as follows:
    #   function : (clicmd1, clicmd2, param[1..n])
    #
    #   - function is the name of the function that will be called
    #     on the server to execute the command
    #
    #   - clicmd1 and clicmd2 is the first and second client
    #     command that identifies which function to call
    #
    # 	NOTE: by design the namespace for the above values is the same
    # 	for all modules, thus a module may overwrite a previously 
    # 	defined value by appearing later in the module load sequence.
    #
    #   - param[1..n] are the parameters that the user must give
    #     in the client.  These arguments will be passed, in the
    #     same order, to the function on the server.  One, and only
    #     one, parameter may be given a trailing + to indicate that
    #     the parameter is loopable
    
    self.all_commands = {
        'a_person' : ('person', 'get', 'number+')
	}

def get_commands(self, uname):
    return {'a_command' :  ('person', 'get', 'number+')}

def get_format_suggestion(self, cmd):
    return { 'a_command' : "Name: %s\nPassword: %s\n" }
The global dict of all commands is built up by first searching the bofhd module, and then all modules in the configfile. Thus, a command in a module may override the default implementation.
$Id: adminprotocol.html,v 1.5 2002/09/20 11:34:01 runefro Exp $