Skip to content

Posts tagged ‘rpc4django’

11
Jan

RPC4Django v0.1.6 is Almost Done!

I have checked the latest changes into subversion. Here is a list of the features supported:

  • Changed the XMLRPC dispatcher to allow sending nil which translates to the Python None. This was already allowed with JSONRPC
  • Cross site request forgery framework support
  • Added cross domain access control
  • Added unit tests for base64 encoded binary
  • Added access to HttpRequest object form inside a called RPC method and associated unit tests

Some of these features were fairly major and I am lucky that I have pretty good unit tests in place. However, since most of these features were user requested, I really hope that I can get some of you guys to run this version in your environment and let me know how it works.

In addition, I’m sorry that I am so late in making this release. As of a week ago, I began a new job (although with the same company). The transition was somewhat taxing, but I should have a little more time freed up for open source work now that everything has settled down.

9
Dec

RPC4Django v0.1.6 Feature Requests

A number of feature requests have come in and I am going to outline what I’m going to try to get done. I hope to put out a release next week (I’ve said that before), but that greatly depends on what features go into it.

Access to HttpRequest

One user submitted feature that seems particularly useful is the ability to access variables and data in the HttpRequest that dispatches the RPC method. For example:

@rpcmethod(permission='myproject.mypermission')
def testmethod(a, b, c):
    # Do something

This RPC method will be authenticated, but it cannot tell who the user is for example. It does not have the ability to read the REMOTE_USER variable. This would be particularly useful if the RPC method was submitting data and needed to know who the submitter was. To rectify this situation, I am proposing sending the HttpRequest object as a keyword argument:

@rpcmethod(permission='myproject.mypermission')
def testmethod(a, b, c, **kwargs):
    if 'REMOTE_USER' in kwargs['request'].META:
        user = request.kwargs.META['REMOTE_USER']
        # Do something

Methods that need access can accept all the additional keyword arguments and methods that don’t care can be written as normal and do not need to change.

Work with the cross site request forgery framework

Django has added a new module to protect against cross site request forgery (CSRF). Unfortunately, if a user adds the django.middleware.csrf.CsrfViewMiddleware to their project, it will break RPC4Django. CSRF protection works by ensuring that all GET requests are side-effect free and then adding a little bit of random data (the CSRF token) to every form that submits via POST. The server can then verify that the correct random data was POSTed and this ensures that the form was submitted from your site and not some remote site.

Unfortunately, RPC is usually intended to be used in a cross site fashion. The fix is relatively painless, but requires some adversarial testing to make it work under Django 1.0, Django 1.1 and Django 1.2. The code (views.py) will look something like this:

try:
    # Django 1.2
    from django.views.decorators.csrf import csrf_exempt
except ImportError:
    try:
        # Django 1.1
        from django.contrib.csrf.middleware import csrf_exempt
    except ImportError:
        # Django 1.0
        csrf_exempt = None

if csrf_exempt is not None:
    csrf_exempt(serve_rpc_request)

I need to test it out very thoroughly and on a number of setups, but I think this code should do it.

HTTP access control

Usually the Javascript XmlHttpRequest object is subject to the same origin policy. This is a security measure that ensures that Javascript will only access data from the same domain, protocol and port as the initial request. There have always been hacks to get around this and the browser vendors are finally providing a uniform, secure way around.

Basically, RPC4Django will need to respond to an HTTP OPTIONS request with the header Access-Control-Allow-Origin specifying what domains are allowed to send requests. Both allowing HTTP access control and which domains are allowed will be options in settings.py.

Patches and feature requests

As always, I am happy to accept patches, but this is what I’ll be working on next week. Please let me know if there are any other important features that you would like to see in RPC4Django.

13
Oct

RPC4Django Update October 2009

A user has requested that RPC4Django support HTTP access control. This is the new preferred method where newer browsers are allowed to make cross domain AJAX requests (with specific constraints) without having to resort to hacks and workarounds like dynamic script tags. I also want to work on JSON class hinting, which is not currently supported. I’m shooting to get this going in the next week before I leave for a Mexican vacation. Swine flu has made the Mexican resorts very reasonable.

Weird Issue on Chrome

In addition, I have noticed that the authenticated demo site does not work in Google Chrome. Is anyone else experiencing this? Any idea why? There’s no problem with Chrome on the demo site not running ssl.

4
Oct

RPC4Django 0.1.5 is Available

Go get it!

I finally completed the version of RPC4Django that uses Django’s authentication system. I blogged about authenticated RPC services previously, and in reality the changes weren’t too major. The only thing I haven’t decided on is what to do in the event a user executes a method with insufficient privileges. Currently, RPC4Django returns HTTP status code 403 (Forbidden), but that seems almost restful. Depending on any feedback I receive, I may change that to actually return an RPC fault which is more RPC like.

In addition, I was contacted about RPC4Django and unicode and I decided to do some testing. As far as I can tell, it supports full unicode without any problem. I wrote some unit tests to verify this and to make sure it continues to support unicode in the future.

Changes
  • Authenticated view that ties in with Django’s auth system
  • Added unicode unit test cases to verify that RPC4Django supports unicode (it does!)
  • Added authenticated demo site (user = pass = rpc4django, self signed certificate)
  • Improved the documentation stylesheet
20
Sep

RPC and Authentication

I’m working on adding support for authenticated service calls to RPC4Django built on top of Django’s user authentication. While doing this, I took a brief look around at how other projects implemented authentication for XMLRPC or JSONRPC. Without exception, they all implemented it such that the username and password was part of the RPC call like so:

from django.contrib.auth import authenticate

def myAuthenticatedMethod(user, password, otherparams):
    # authenticate user
    user = authenticate(username=user, password=password)

    # verify the user is valid and has the appropriate permissions
    # perform method actions

Some of them abstracted the actual username and password checking into a decorator, but in the end, the RPC call had the username and password in the parameters. It seemed bulky and out of place. This led to an analysis about authentication and authorization and what should be handled where. As a little spoiler, I don’t like the idea of sending the username and password in the RPC parameters one bit.

Authentication & Authorization

In applications, authentication is the process that confirms the identity of the user. Usually this takes the form of a login form, HTTP basic authentication, or something similar. Authorization is the process to determine whether the user has sufficient privileges to perform the specified action. This takes the form of permission checks based on the authenticated user. Therefore, authentication must come before authorization.

Fortunately, Django’s user authentication helps with both authentication and authorization. The authenticate method checks a username and password against the set of Django users and gets the user object if everything goes well. Once this user object is retrieved, permissions can be checked using the has_perm method. Django has a pretty easy way to create new permissions based on your application’s logic. Permissions have to be checked at the specific method level since permissions are closely tied to the application logic. I like the idea of abstracting much of it into a decorator though. The only remaining question is: where does the username and password come from?

An Example from the Real World

Why should every RPC method need to be specially written to accept the login credentials and authenticate the user? This makes the method only usable as an RPC method and not useful at all to the rest of the project which is bad for code reuse. Amazon s3, a commercial web service for storing files, is a perfect example of the proper way to authenticate and authorize users. With s3, the login information is contained in the HTTP header in a manner similar to HTTP basic authentication and in this way the request can be rejected earlier based on login credentials before the request even routes to the proper method requested. Permission checking, seeing whether the user is allowed to store new files for example, still needs to be done at the method level but at least the identity of the user is known.

Implementation and Demo

For RPC4Django, I’m proposing that authentication be handled at a higher level — with basic HTTP authentication for example. To illustrate this, I set up an https RPC4Django demo site that requires a username and password (rpc4django/rpc4django). The demo site requires that you accept a self-signed certificate. Using python, it is possible to send authenticated requests like so:

from xmlrpclib import ServerProxy
s = ServerProxy('https://rpc4django:rpc4django@rpcauth.davidfischer.name/')
s.system.listMethods()

The next step is to modify RPC4Django to actually be able to specify permissions for specific methods and to actually log in the users. Expect a release this week.