views:

55

answers:

2

I'm working on a web mapping service and would like to provide my users with a Python API that they can use to create custom plugins. These plugins would be running on my server so I'm trying to lock down Python as much as possible.

To ensure that users can't access files they are not supposed to, I'm planning on running the plugins inside of a PyPy sandboxed interpreter.

The last large hurdle that I'm trying to overcome is how to overcome is with the API itself. I have a database API that will allow the user to make controlled queries to the database. For example, I have a select(column,condition) function that will allow users to retrieve items from the database but they will be restricted to a table. Then, there is a private function _query(sql) that takes raw SQL commands and executes them on the server

The problem is that Python (at least to my knowledge) provides no way of preventing users from calling the query function directly and nuking my database. In order to prevent this, I was thinking of breaking my API into two parts:

-------------   pipe   --------------      ------------
| publicAPI | -------> | privateAPI | ---> | database |
-------------          --------------      ------------

So publicAPI would basically be a proxy API communicating with the main API via a pipe. publicAPI would only contain proxies to the public API functions, users would be unable to get a hold of the private elements (such as _query(sql)).

Do you think this is a viable solution? Am I making way too much work for myself by overlooking a simpler solution?

Thanks so much for your help!

+2  A: 

This looks like a clean way to implement this to me. I believe it's also sometimes referred to as the "Facade" design pattern.

In python this is very easy to implement using explicit method delegation (a short snippet to give you a general idea):

class FacadingAPI():
    def __init__(fullapi_instance):
        self.select = fullapi_instance.select # method delegating
        ...
ChristopheD
A: 

There are many ways that you can do this. I tend to have a tuple with all the function names that are available and then check if the function being called is in the tuple, if not then throw an error.

e.g.

funcs = ("available","functions","here")

if (calledFunction in funcs):
  #do something
else:
  #throw error

or you can take the approach that google have on their App Engine page

http://code.google.com/appengine/articles/rpc.html

AutomatedTester